How to automatically enter a state parameter
annotation
Hi I am using angular + ui-router in my project, I have a huge number of nested states and different views, which in turn contain a huge number of different inputs, the user fills in these inputs gradually step by step.
Problem
Sometimes users need additional information located in the previous step, and the "Back" button of browsers helps the user to look into this data, but as soon as the user clicks on it, the information that he has already entered is lost due to the state transition, which is obviously badly.
Strategy
To overcome the described problem, I have the following plan:
- Associate each custom "navigation" (assuming this is the correct term) with a random id
- To prevent problems of inheritance inheritance and serialization, instead of putting the viewmodel in
$scope
use a regular javascript object that will store the immediate values ββbound to the UI. - Add an observer to search for changes in this "repository"
- Once the change is noticed, serialize the object and save it
Clarifications
Why do we need a random parameter in the URL?
We don't want to store all of the data in the url as there can be quite a lot of data that won't fit in the url. Therefore, to provide guarantees, the URL will not break, we only put a small random GUID / UUID in it, which later allows us to retrieve the data associated with the current "navigation" using this random GUID / UUID.
Vault
There is plenty of available storage scenarios: LocalStorage
, IndexedDB
, WebSQL
, Session Storage
, you name it, but because of their cross-tabs, cross-browser-specific nature of the browser would be difficult to manipulate and manage all data that fall within the store. The implementation will be buggy / server side support may be required.
Thus, the most elegant storage strategy for this scenario would be to store the data in a special variable window.name
that is capable of storing data between requests. This way, the data is safe until you close the tab.
Question
On behalf of everything written above, I have a root view called "view" that has a state parameter id
(this is a random GUID / UUID)
$stateProvider.state('view', {
url: '/view/{id}',
controller: 'view',
templateUrl: 'views/view.html'
});
All other views follow from this view, is there a way to make a directive ui-sref
to automatically inject a random GUID / UUID into the state parameter of id
my root view instead of writing each time ui-sref
like
<a ui-sref="view({id:guid()}).someNestedView({someNestedParam: getParam()})"
I would like to have something like:
<a ui-sref="view.someNestedView({someNestedParam: getParam()})"
source to share
AOP and Decorator image is the answer. A full description can be found here:
Experiment: Designing Directives from Jesus Rodriguez
A similar solution, as described below, could be observed:
Changing default behavior of $ state.go () in ui.router to reload by default
How does it work? There is a link to a working example
In this case, we don't decide which source the random GUID comes from. Let's keep it simple at runtime:
var guidFromSomeSource = '70F81249-2487-47B8-9ADF-603F796FF999';
We can now introduce a decorator like this:
angular
.module('MyApp')
.config(function ($provide) {
$provide.decorator('$state', function ($delegate) {
// let locally use 'state' name
var state = $delegate;
// let extend this object with new function
// 'baseGo', which in fact, will keep the reference
// to the original 'go' function
state.baseGo = state.go;
// here comes our new 'go' decoration
var go = function (to, params, options) {
params = params || {};
// only in case of missing 'id'
// append our random/constant 'GUID'
if (angular.isUndefined(params.id)) {
params.id = guidFromSomeSource;
}
// return processing to the 'baseGo' - original
this.baseGo(to, params, options);
};
// assign new 'go', right now decorating the old 'go'
state.go = go;
return $delegate;
});
})
The code should be self-explanatory, check it out in action here
source to share