ExtJS 5/6 : FileField/FileUploadFile : reading data

Introduction

I have a “filefield” or “fileuploadfield” in ExtJS, and I’d like to read directly its content directly into the browser, when user selects a file.

It is useful when you’d like to display an image for example, as soon as the user selects it.

How To Proceed

First of all, you need to declare the “filefield” with a listener on “change” event. For example:

{
    xtype: 'filefield'
    ,fieldLabel: "File: "
    ,labelWidth: 70
    ,anchor: '100%'
    ,buttonOnly: true // hide text field below button
    ,buttonText: "Select a picture"
    ,listeners: {
        'change':  'onMediaChange'
    }
}

and in the Controller, the handler:

onMediaChange: function(widget, value, eOpts ) {
  var files = event.target.files
      self = this; // the controller
  if (!files || files.length == 0) return; // make sure we got something
  // Let's read content as file
  var reader = new FileReader();
  reader.onload = function (e) {
    // image content is in e.target.result
    // we can then put it into img.src, for example
    self.lookupReference('myImg').setSrc(e.target.result);
  };
  reader.readAsDataURL(files[0]);
}

and that’s it!

Memo : Nginx proxy for Wildly

Introduction

Quick setup of Nginx to have redirection on Wildfly instance based on uri path

Setup

Edit your server configuration file within

/etc/nginx/sites-available

Change “location” section to (for example):

        location / {
                # wildfly redirect
                location /app {
                        proxy_set_header   X-Real-IP $remote_addr;
                        proxy_set_header   Host      $http_host;
                        proxy_pass http://127.0.0.1:8080;
                        proxy_redirect http://127.0.0.1:8080 http://www.example.com;
                }
                # First attempt to serve request as file, then
                # as directory, then fall back to displaying a 404.
                try_files $uri $uri/ =404;
        }

Here, only path starting with /app will be fully redirected to WildFly, i.e. your main  Application.java path should be @Path(“/app”).

ExtJS : Accessing Application from anywhere

In ExtJS, “Application” is handling and containing a lot of stuff. Among other things, useful getters are:

  • getStore(‘store_name’) : retrieve a store
  • getRoutes()  : get Routes

How to retrieve current Application?

In fact, is is really simple. Let’s imagine that your App namespace is ‘MyApp’; then it can be retrieve using:

MyApp.getApplication()

Update (March 13th): you can also use

MyApp.app

Git – Remote Branch – Tips

A little memo when I need to start a git project from a remote branch and server:

git init
git remote add origin [server]
git fetch origin
git checkout -b [localbranchname] origin/[remotebranchname]

The 2 last lines are the most important. To view all branches:

git branch -v -a

For bitbucket (my favorite git repo), [server] will be something like

git@bitbucket.org:[login]/[project].git

 

Android: EditText Login/Password : intercept ‘OK’ and ‘ENTER’ on a LoginForm

Quick tips on a Login Form in an Android App, to enhance user experience: intercept ‘Enter’ in a TextView or ‘OK’ in a Numeric-only TextView

My Login Form is with a Relative Layout. Note that the Password field is numeric-only.

<EditText
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/start_userid"
    android:hint="@string/start_userid"
    android:layout_alignParentTop="true"
    android:layout_marginTop="50dp"
    android:layout_centerHorizontal="true"
    />
<EditText
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:inputType="numberPassword"
 android:ems="10"
 android:id="@+id/start_passwd"
 android:hint="@string/start_password"
 android:layout_below="@+id/start_userid"
 android:layout_centerHorizontal="true"
 />

The code to intercept “Enter” Key in UserId field, and “OK” in numeric-only Password field is:

mUserId = (EditText) findViewById(R.id.start_userid);
mUserPassword = (EditText) findViewById(R.id.start_passwd);

mUserId.setOnEditorActionListener(
  new TextView.OnEditorActionListener() {
    @Override
    public boolean onEditorAction(TextView textView, int actionId, KeyEvent keyEvent) {
        if (actionId == EditorInfo.IME_NULL && 
             keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
            mUserPassword.requestFocus();
        }
        return true;
    }
});

mUserPassword.setOnEditorActionListener(
  new TextView.OnEditorActionListener() {
    @Override
    public boolean onEditorAction(TextView textView, int actionId, KeyEvent keyEvent) {
        if (actionId == EditorInfo.IME_ACTION_DONE) {
            doLogin(); // check login & so on
        }
        return true;
    }
});

Symfony 2 : Avoid doctrine’s memory leaks with commands

While running some specific long-time import processes through Doctrine by running a Symfony 2 command, I noticed some memory leaks.

I’m using MongoDB on top of doctrine.

For example:
First import : 22 MB used
Last import (100k+): 500+ MB used

Couple of tips:

  1. Call $dm->clear() regularly to clean up doctrine cache. But, do not forget that all objects in cache will be swept
  2. This is the REAL tip: add –no-debug to your command line
php app/console --no-debug my:bundle:command

The 1st tip helps a little bit, the 2nd one is very efficient. And it has another impact: it speeds up the execution.

ExtJS 5 : get a store from anywhere in your app

In the app I’m working on, I have multiple stores, and I need to get an access to any of them from anywhere.

There are multiple approaches: store (!) the Stores’list in a global variable or in an App variable, …

In fact, there is a much more simple way. When you declare your store, setup a “storeId” parameter.

Ext.create('Ext.data.Store',
{
  model: 'My.Model',
  storeId: 'my-model-store'
  [...]
}

Then, to easily access this store from anywhere:

var store = Ext.data.StoreManager.lookup('my-model-store');

Let’s be honest : it is nothing more than a global variable and you can achieve the same easily; anyway, it conveniently rocks!

SF2 : How to create a Service in 5 minutes ? Why ?

Let’s have a shortcut : a service is a set of specialized functions, packaged into a specific bundle. On a global approach, it’s like a dedicated task.

In my dev, I love service. Some of them I have written are for example in charge of:

  • SMS sending (using multiple providers, completely transparent)
  • Geocoding an address (using a cache, but also again trying multiple geocoding engines),
  • Processing emails,
  • Generating documents,

Let’s start

  1. Let’s create a new bundle (called AB3/ServiceBundle).
    php app/console generate:bundle

    Usually, I use “annotation” to declare the project.

  2. Create a new controller (MainController) in AB3/ServiceBundle/Controller directory with couple of methods
    namespace AB3\ServiceBundle\Controller;
    class ServiceController {
      public function funcOne() { return "funcOne"; }
      public function funcTwo() { return "funcTwo"; }
    }
    
  3. Here is the main and most important part: declare your service. By default, Symfony2 uses xml file, which I don’t like. So, let’s do it using annotation instead, which is more convenient IMO.
    In AB3\ServiceBundle\DependencyInjection, edit “AB3ServiceExtension.php” and replace

    $loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
    $loader->load('services.xml');

    by

    $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
    $loader->load('services.yml');
  4. In AB3\ServiceBundle\Resources\config. Delete services.xml and create a new services.yml file instead, where we will declare the service entry points as below:
    parameters:
        my.service.class: AB3\ServiceBundle\Controller\CacheController
    
    services:
        my.service:
            class: "%gesloc.cache.class%"

    2 important notes:
    – Under parameters, we declare the class name.
    – But the real stuff is under services: there, we declare the service name (my.service) and the class it belongs to

  5. Then to consume your service from any external controller:
    public function indexAction() {
    [...]
        $this->get('my.service')->funcOne();
        $this->get('my.service')->funcTwo();
    [...]
    }

    And that’s all !!!

ExtJS 5/6 : Localization / i18n / l10n

Ok, let’s be honest. Current localization in ExtJS 5.x is a mess and everything but efficient at this time.

IMO, the best approach is to set everything outside. The approach I’m using is quite simple and is deeply inspired from a YAML approach (and next release of my class Lang/i8n class will support YAML directly).

The cons: only one : At this time, you cannot change the lang dynamically/on-the-fly. Language is set just before Main App starts.

The “YAM-inspired” implementation:

Ext.define('Lang',{
    singleton : true

    ,config : {
        currentLang : null,
        defaultLang : 'fr'
    }
// Here starts string declarations
    ,strings: {
        'fr_FR' : {
            desktop: {
                map : "Carte"              
            }
            ,settings: {
                stretch: "Ajuster/Etirer"
                ,wallpaper: "Fond d'écran"
                ,preview: "Aperçu"
                ,none: "Aucun"
            }
        }
        ,'us_US' : {
            desktop: {
                map : "Map"
            }
            ,settings: {
                stretch: "Stretch to fit"
                ,wallpaper: "Wallpaper"
                ,preview: "Preview"
                ,none: "None"
            }
        }
// end of string declarations
        // shortcuts
        ,fr : 'fr_FR'
        ,en : 'us_US'
        ,us : 'us_US'
    }

    ,getStrings: function(lang) {
        if (!lang || !Ext.isDefined(this.strings[lang]))
            lang=this.getDefaultLang();
        if (Ext.isString(this.strings[lang])) // got an aliase
            lang = this.strings[lang];
        return Ext.isDefined(this.strings[lang])
                ? this.strings[lang]
                : { };
    }
    // Do the translation
    ,t : function(label, lang) {
        var path = label.toLowerCase().split('.'),
            p = this.getStrings(lang); // strings
        for (var i = 0; i<path.length; i++) {
            if (Ext.isDefined( p[ path[i] ]))
                p = p[ path[i] ];
            else return '<<' + label + '>>'; // not found
        }
        return p;
    }

    ,constructor : function(config) {
        this.initConfig(config);
        if (!this.getCurrentLang())
            this.setCurrentLang( this.getDefaultLang());
    }
});
var i18n = function(label, lang) { return Lang.t(label, lang); };

How to use it :
– in main app, add ‘Lang’ to requires  (it Lang is in main directory)

requires: [
    'Lang',
]

– set language : Lang.SetCurrentLang(‘en’) for example
– get a string : i18n(“settings.wallpaper”) or Lang.t(“settings.wallpaper”)

Improvements/ToDo List

  • Import YAML or JSON directly as a lang file (ie not built-in)
  • Change current language on the fly, without reloading