Automatic saving of ng model values
The current question is a logical continuation of this question
annotation
Hi I am trying to automatically save values ng-model
based on history step. This way, when a person clicks the browser back / forward button, they get the same values โโin their inputs / checkboxes / etc. which were there before he left (including user changes).
I am using browser session storage (Web Storage) to store values ng-model
. this kind of storage works on a tab / session basis in a session, so it's absolutely okay to use it with this kind of problem.
Through 'ui-router' I can bind each user navigation to a unique UUID (GUID) which is later used to retrieve bucket
which contains all the stored values $scope
.
I even go out with an implementation that (partially) works, you can find it at the bottom of this question.
Problem
I am currently having a problem keeping values โโacross the entire scope. I currently use a key ng-model
as a key for a bucket, for example, in ng-model="city.name"
I use "city.name"
as a key for my bucket. In this example, the resulting bucket that goes into the session store would look like
var bucket === {
"city.name": "Some city name"
}
...
$window.sessionStorage.setItem(viewId, bucket);
Obviously, if we iterate over the list of cities, we can get a dozen of these keys. To solve this problem, I need a type id
that uniquely identifies the current location ng-model
within the entire structure $scope
.
I cannot use it $scope.$id
for this purpose because it changes every time the region is recreated. So, one of the ideas I came across is to calculate the current relative position $scope
in the $ scope tree using a property $scope
$$prevSibling
and concatenate it with the same position as its parent and parent parent until we reach $ rootScope. this is how i see it:
$rootScope.$index = function() {
return this.$$index || (this.$$index = !this.$$prevSibling ? 0 : this.$$prevSibling.$index());
};
$rootScope.$uid = function() {
return this.$$uid || (this.$$uid = (!this.$parent ? '' : this.$parent.$uid()) + ',' + this.$index());
};
The call $scope.$uid()
will return a string value like this '0,4,6,2,1,123'
that uniquely identifies the current position $scope
in the scope hierarchy. This value can be combined with a key ng-model
and will have the same bucket
{
"0,4,6,2,1,1-city.name": "Some city name 1"
"0,4,6,2,1,2-city.name": "Some city name 2"
"0,4,6,2,1,3-city.name": "Some city name 3"
...
"0,4,6,2,1,123-city.name": "Some city name 123"
}
Question
The implemented implementation will obviously fail when $scope
dynamically creating / destroying during "navigation", in other words it $scope
$$prevSibling
may change. I'm not sure if $ scopes can be added (which will index f * ck and break everything apart), but I'm pretty sure the scopes can be destroyed and removed, resulting in inconsistent indexing. So obviously I have a general question, what do you think about this problem, are there any better solutions to this problem from your point of view.
Thank you in advance!
Existing implementation
I have decorated ng-model
to save every change in session store, changes fade and persist after a 500ms delay, every change that happened in those 500ms restarts the previous timer.
$provide.decorator('ngModelDirective', function ($delegate) {
var ngModel = $delegate[0], controller = ngModel.controller;
var persisted, viewId;
ngModel.controller = ['$scope', '$state', '$element', '$attrs', '$injector', '$parse', '$window', '$timeout', function ($scope, $state, $element, $attrs, $injector, $parse, $window, $timeout) {
if (viewId !== $state.params.viewId) {
viewId = $state.params.viewId;
persisted = $window.sessionStorage.getItem(viewId);
}
if ('ng-model-non-persisted' in $attrs) {
} else {
var ngModelGet = $parse($attrs.ngModel),
ngModelSet = ngModelGet.assign;
if (ngModelSet) { // Otherwise base call will throw an exception
if (persisted) {
persisted = angular.fromJson(persisted);
var model = ngModelGet(persisted);
if (model !== void 0) {
ngModelSet($scope, model);
}
} else {
persisted = {};
}
var throttle, cachedValue;
$scope.$watch(function () {
var value = ngModelGet($scope);
if (cachedValue !== value) {
cachedValue = value;
ngModelSet(persisted, value);
if (throttle) {
$timeout.cancel(throttle);
}
throttle = $timeout(function() {
$window.sessionStorage.setItem(viewId, angular.toJson(persisted));
throttle = null;
}, 500);
}
});
}
}
$injector.invoke(controller, this, {
'$scope': $scope,
'$element': $element,
'$attrs': $attrs
});
}];
return $delegate;
});
source to share
No one has answered this question yet