An Extjs plugin that hides/disables a component based on the user roles provided and user roles required for a component
This is similar to previous post, only difference is that the keys and translations are loaded from a remote source.
For an enterprise level app, its not a good idea to store huge list of keys & translations inside the app itself because it will become unmaintainable at some point and moreover every change would require redeploy of the app. So ideally there should be a remote store where we can store and manage these keys and their corresponding translations in all languages. Below example illustrates how we can fetch I18n keys from a remote endpoint and store them in an in-memory store that can be loaded once at app load and then used for all the translations.
ExtJs components does support internalization but for the other content present in component (titles, labels, error messages etc.) we often need to have a utility which can be used to translate the keys to their corresponding translations based on the selected language. Below is one way of creating such a utility which works based on the keys and translations stored inside the app that can be used for adding I18n keys for texts where translations are required.
Grids in Extjs provide a lot of functionality out of the box, like hiding columns, applying sorters/filters, re-sizing column width etc. So it is very desirable by the end users to be able to save the state of grid so that they don’t have to apply those settings to grid each time the grid is rendered.
Extjs provides a very easy and clean way to setup all its components to save their state to browser’s localStorage or in the form of cookies through its Ext.state.LocalStorageProvider and Ext.state.CookieProvider respectively. In this example we’ll explore how to setup any component to save its state to localStorage. The configuration basically requires two steps :
- Configuring a state provider
- Configuring component to save its state
Configuring a state provider
This can be done in the init method of the application where we can initialize the state provider
Configuring component to save its state
We need to mark each component (that needs to be stateful) as stateful and provide it a stateId for state manager to save that component’s state
That’s it! Now the state of the component should be saved in the browser’s local storage. You can verify this by checking the local storage in dev tools or just try hiding some columns in a stateful grid and reload app to check if the grid remembers your settings.
If your extjs development workflow is based on Sencha Architect then you must have already faced some issues while trying to make gmaps api work with your sencha app. Actually its not that straightforward task to add gmaps as an external js resource as it is for adding other js resources in Sencha Architect. Problem is that gmaps (if added as a remote js resource ) loader interferes with the sencha extjs microloader and hence the gmaps api is not properly utilized.
If you have a requirement where you want to utilize the gmaps functionality within your sencha app then you could follow along the below steps to integrate gmaps api with your app.
1. Add the gmap script url in the index.html (you need to manually edit index.html and make sure overwriting index.html is disabled on build, because otherwise your index.html would be reset after each app build).
2. Lets say we have a Container named googlemapcontainer where we want to show the googlemap. Initially it is hidden, we would want to show it only when we have coordinates where the google map should be centered.
a. Let us assume that the coordinates for map center comes from a remote api, we store the response (having coordinates) on viewModel of the current view where map needs to be shown.
b. Define an addGmap function on view controller that adds the gmap in googlemapcontainer. it takes the longitude and latitude values from viewModel. A listener “afterrender” is defined which does the task of getting coordinates from viewModel and creating a map and map marker.
c. Define a showMap function on view controller to get coordinates through ajax and make googlemapcontainer visible.
All the code changes are available in the below snippets:
For a simple Extjs app it would be desirable to have a dedicated User class which captures the logged in user details so that certain components that should be visible/hidden based on the user roles. So we can define such a User class and initialize the user’s roles and other details just after login. Below is one way to implement such a functionality where user details are captured and re-used for checking current logged in user roles.
1. Create a new singleton Extjs User class (User.js).
2. Get the User rights through ajax call (this can be done at the app startup in the launch method, or just after a successful login) and save them for reuse (app.js).
3. Use saved user to check whether logged in user has certian role or not. Lets say we want to show certain menu items based on roles (usage.js)
Generally an ExtJs app takes good amount of time to get loaded in the browser when opened for the first time. For really large apps it can take a few seconds to load the first page as well, so user might be staring at a blank screen and wonder what wrong has happened. So it is always good to show something like “App is loading” message with some loading animation to inform user that everything is alright and application is about to start.
Here is an attempt to provide such a loading spinner until the extjs app is ready for use. Below steps are specific for Sencha Architect, but the concept would still be same if implementation is done without the SA tool.
- Your index.html should look like below after creating a project using SA.
Just Add a new <div> inside Body tag.
<div id=”initialLoader” class=”loader”></div>
So your index.html should look like below after this.
2. Create a launch function under Application in SA and add below code to check for an element with id “initialLoader” and remove it when app loading is completed.
3. Create a custom scss resource and add below css rules to give some style to the added div.
4. Disable “overwrite index.html” in your SA preferences so that index.html changes are not overridden after each build.
5. Build and see preview, you should see a loading spinner animation before your app is fully loaded into browser.
There could be requirement when user needs to fill a large form with multiple fields, it would make sense to use the enter key instead of tab to direct user to next form field, so we can achieve this functionality by creating a custom directive and using that with the form fields that need to possess this “auto focus next element on enter key” behavior.
One more use case where such a custom directive could come handy is when the user have a barcode scanner and he/she just need to be able to fill through form fields without touching keyboard/mouse. A typical barcode scanner will scan the barcode, key-in the barcode into focused field and then will fire an enter key pressed event. So a custom directive like below would be a very easy way to implement such behavior.
Most of the times we need to configure a timeout for all the ajax calls fired from anywhere in the sencha application. This can be done by simply setting up some properties for the Ext.Ajax, Ext.data.proxy and Ext.data.connection classes during application startup.
You may add a function setup to Application through Sencha Architect just to keep this code in a separate function (otherwise you may add the code to launch method as well. Below is the configuration required for setting global default ajax timeouts
Above code sets the timeout to 300000 ms and additionally disables the default xhr headers to false (disabling this might save you some time in case you face any issues when the headers provided to your ajax calls seems to be changed)
Edit 05-01-2017: For Extjs 6.2 just adding below to launch method should handle the default timeout for ajax in your application :
In most of the sencha extjs applications, its always good practice to have a global exception handler so that any common exceptions from server can be handled in a uniform way from a single place. One such instance is, having a global exception handler for handling HTTP status 401. This status is returned by server to the client application when the user is not authenticated to access a server side functionality.
From UI perspective, two main use cases when HTTP 401 can be thrown could be :
- User tries to open an app for the first time, usually a login screen is presented where a user can enter the credentials and log in to the app. If the credentials entered are incorrect then an HTTP status 401 is returned by server. User should not be able to close login screen until correct credentials are provided.
- User has successfully logged in to app and after some time, the session on server for this user expires. So any subsequent api requests to server will return HTTP 401 unless a session is again established. In such a case, usually user is again presented a login pop up window to enter credentials and continue working on the app.
So to achieve this in a Sencha app, we can setup up a global exception handler for all ajax calls by adding the below code in the application’s launch function.
Above code basically routes the application to login route where the actual login to open up a login window can be written.
In sencha architect this can be done by simply selecting Application, adding a launch function (if not already present) and adding the above code.