zoomsphere / ngx-store

Angular decorators to automagically keep variables in HTML5 LocalStorage, SessionStorage, cookies; injectable services for managing and listening to data changes and a bit more.
https://www.npmjs.com/package/ngx-store
ISC License
167 stars 41 forks source link

Missing local storage key #19

Closed HarelM closed 7 years ago

HarelM commented 7 years ago

Hi,

I'm not sure I'll be able to reproduce it but I have the following code:

    @LocalStorage()
    private storedBaseLayers: Common.LayerData[] = [];
    @LocalStorage()
    private storedOverlays: Common.LayerData[] = [];
    @LocalStorage()
    private activeOverlayKeys: string[] = [];
    @LocalStorage()
    private selectedBaseLayerKey: string = LayersService.ISRAEL_HIKING_MAP;

For some reason I don't see the ngx_activeOverlayKeys value in the local storage keys: image The fact that this variable is not in the local storage list is less alarming than the fact that it doesn't get into local storage so every time I push an object to this array I get an error:

ERROR TypeError: Array.prototype.push called on null or undefined
    at push (<anonymous>)
    at Array.prototype.(anonymous function) [as push] (http://localhost:58231/vendor.bundle.js:37294:58)

Does this library holds a list of already added item or something? I'm not sure how to fix this... Thoughts are welcome... :-/

DanielKucal commented 7 years ago

Hi @HarelM, keys of stored items are hold in localStorageService.keys field - please check if it contains all ngx-stored items... Are you sure your activeOverlayKeys variable is not being cleared somewhere? By the way, did you set keys for e.g. 4x4_selected and Points of Interest_visibility manually? Because variables can't have such names and it looks strange... Maybe it can cause problems on some browsers...

HarelM commented 7 years ago

Yup... I can send you a link to be able to debug my site with unminimized if it will help out. I'm pretty clueless right now (I know I can switch to localstorageservice, but I rather not...)

DanielKucal commented 7 years ago

LocalStorageService.keys includes items set by decorators too, please show me its content. Would be great if you can enable debugMode (in global variable named NGXSTORE_CONFIG) in your project and paste the logs, it'd probably give us the source of this problem.

HarelM commented 7 years ago

Can't see the value of LocalStorageService.keys for some reason, can you explain how to enable debug mode?

DanielKucal commented 7 years ago

The fastest way is to add to index.html the following code before other scripts:

<script>
var NGXSTORE_CONFIG = {
  debugMode: true
};
</script>

You should use Angular DI to inject LocalStorageService:


constructor(localStorageService: LocalStorageService) {
  console.log('local storage keys:', localStorageService.keys);
}
HarelM commented 7 years ago

Key are the following:

0
:
"ngx_4x4_selected"
1
:
"ngx_Bicycle_selected"
2
:
"ngx_Camping_selected"
3
:
"ngx_Hiking_selected"
4
:
"ngx_Historic_selected"
5
:
"ngx_Natural_selected"
6
:
"ngx_Other_selected"
7
:
"ngx_Points of Interest_visibility"
8
:
"ngx_Routes_visibility"
9
:
"ngx_Viewpoint_selected"
10
:
"ngx_Water_selected"
11
:
"ngx_center"
12
:
"ngx_currentLanguage"
13
:
"ngx_isAdvanced"
14
:
"ngx_selectedBaseLayerKey"
15
:
"ngx_storedBaseLayers"
16
:
"ngx_storedOverlays"
17
:
"ngx_token"
18
:
"ngx_zoom"
19
:
"token"
20
:
"currentLanguage"
21
:
"center"
22
:
"zoom"
23
:
"isRoutingPerPoint"
24
:
"routingType"
25
:
"routeOpacity"
26
:
"storedBaseLayers"
27
:
"storedOverlays"
28
:
"activeOverlayKeys"
29
:
"selectedBaseLayerKey"
30
:
"storedUserEmail"
31
:
"isAdvanced"

Which is more than 23 which are those stored in localStorage in the browser...

HarelM commented 7 years ago

Debug trace:

Line 2: debug.js:61 [ngx-store] CacheItem for token CacheItem {name: "token", targets: Array(1), services: Array(1), utilities: Array(1), _key: "token", …}
    Line 3: debug.js:61 [ngx-store] Created new CacheItem for currentLanguage
    Line 4: debug.js:61 [ngx-store] CacheItem for currentLanguage CacheItem {name: "currentLanguage", targets: Array(1), services: Array(1), utilities: Array(1), _key: "currentLanguage", …}
    Line 5: debug.js:61 [ngx-store] Created new CacheItem for center
    Line 6: debug.js:61 [ngx-store] CacheItem for center CacheItem {name: "center", targets: Array(1), services: Array(1), utilities: Array(1), _key: "center", …}
    Line 7: debug.js:61 [ngx-store] Created new CacheItem for zoom
    Line 8: debug.js:61 [ngx-store] CacheItem for zoom CacheItem {name: "zoom", targets: Array(1), services: Array(1), utilities: Array(1), _key: "zoom", …}
    Line 9: debug.js:61 [ngx-store] Created new CacheItem for isRoutingPerPoint
    Line 10: debug.js:61 [ngx-store] CacheItem for isRoutingPerPoint CacheItem {name: "isRoutingPerPoint", targets: Array(1), services: Array(1), utilities: Array(1), _key: "isRoutingPerPoint", …}
    Line 11: debug.js:61 [ngx-store] Created new CacheItem for routingType
    Line 12: debug.js:61 [ngx-store] CacheItem for routingType CacheItem {name: "routingType", targets: Array(1), services: Array(1), utilities: Array(1), _key: "routingType", …}
    Line 13: debug.js:61 [ngx-store] Created new CacheItem for routeOpacity
    Line 14: debug.js:61 [ngx-store] CacheItem for routeOpacity CacheItem {name: "routeOpacity", targets: Array(1), services: Array(1), utilities: Array(1), _key: "routeOpacity", …}
    Line 15: debug.js:61 [ngx-store] Created new CacheItem for storedBaseLayers
    Line 16: debug.js:61 [ngx-store] CacheItem for storedBaseLayers CacheItem {name: "storedBaseLayers", targets: Array(1), services: Array(1), utilities: Array(1), _key: "storedBaseLayers", …}
    Line 17: debug.js:61 [ngx-store] Created new CacheItem for storedOverlays
    Line 18: debug.js:61 [ngx-store] CacheItem for storedOverlays CacheItem {name: "storedOverlays", targets: Array(1), services: Array(1), utilities: Array(1), _key: "storedOverlays", …}
    Line 19: debug.js:61 [ngx-store] Created new CacheItem for activeOverlayKeys
    Line 20: debug.js:61 [ngx-store] CacheItem for activeOverlayKeys CacheItem {name: "activeOverlayKeys", targets: Array(1), services: Array(1), utilities: Array(1), _key: "activeOverlayKeys", …}
    Line 21: debug.js:61 [ngx-store] Created new CacheItem for selectedBaseLayerKey
    Line 22: debug.js:61 [ngx-store] CacheItem for selectedBaseLayerKey CacheItem {name: "selectedBaseLayerKey", targets: Array(1), services: Array(1), utilities: Array(1), _key: "selectedBaseLayerKey", …}
    Line 23: debug.js:61 [ngx-store] Created new CacheItem for storedUserEmail
    Line 24: debug.js:61 [ngx-store] CacheItem for storedUserEmail CacheItem {name: "storedUserEmail", targets: Array(1), services: Array(1), utilities: Array(1), _key: "storedUserEmail", …}
    Line 25: debug.js:61 [ngx-store] Created new CacheItem for isAdvanced
    Line 26: debug.js:61 [ngx-store] CacheItem for isAdvanced CacheItem {name: "isAdvanced", targets: Array(1), services: Array(1), utilities: Array(1), _key: "isAdvanced", …}
    Line 78: debug.js:61 [ngx-store] initial value for currentLanguage in ResourcesService {code: "he", rtl: true, label: "עברית", tilesFolder: "/Hebrew"}
    Line 80: debug.js:61 [ngx-store] initial value for center in MapService {lat: 31.710863696254325, lng: 35.14461994171143}
    Line 82: debug.js:61 [ngx-store] initial value for zoom in MapService 14
    Line 84: debug.js:61 [ngx-store] initial value for token in AuthorizationService "6AveNWUUDcOKXJWCrFX2nam30cVuhzfQYqu6YqUz";"IEjy6EqRJVS4ryNxa6lESn4shDY5yGS2JKsgIgL7"
    Line 86: debug.js:61 [ngx-store] initial value for storedBaseLayers in LayersService []
    Line 88: debug.js:61 [ngx-store] initial value for storedOverlays in LayersService []
    Line 90: debug.js:61 [ngx-store] initial value for activeOverlayKeys in LayersService []
    Line 92: debug.js:61 [ngx-store] initial value for selectedBaseLayerKey in LayersService IHM
    Line 94: debug.js:61 [ngx-store] initial value for isRoutingPerPoint in RouteLayerFactory true
    Line 96: debug.js:61 [ngx-store] initial value for routingType in RouteLayerFactory Hike
    Line 98: debug.js:61 [ngx-store] initial value for routeOpacity in RouteLayerFactory 0.5
HarelM commented 7 years ago

Getting null in cache-item.js:

var _loop_1 = function (method) {
                prototype[method] = function () {
                    var value = _self.readValue(config); // value = null.
DanielKucal commented 7 years ago

Could you expand logs for activeOverlayKeys please? I think there should also be log about saved value... Anyway, the value seems to bet properly... Are you sure you are not using localStorage on this field directly? Because initial values are no longer saved since few versions...

HarelM commented 7 years ago

For some reason I can't copy the values from Chrome, I hope you'll be able to read this: Let me know what you are looking for: image image image image

DanielKucal commented 7 years ago

You can also try changing this line:

_.remove(this.activeOverlayKeys, (keyToFind) => keyToFind === overlay.key);

to:

this.activeOverlayKeys.filter((keyToFind) => keyToFind !== overlay.key);

It can be reason, because _.remove mutates the array...

HarelM commented 7 years ago

I'll try, but I don't think that's it as I used splice and it didn't seem to help.

HarelM commented 7 years ago

Nope :-( same error message. The above _.remove is never executed for this scenario...

DanielKucal commented 7 years ago

Don't you have any logs starting by "Saving value for activeOverlayKeys"?

HarelM commented 7 years ago
CacheItem#saveValue for activeOverlayKeys in LayersService
[ngx-store] new value:  []
debug.js:61 [ngx-store] previous value:  null
debug.js:61 [ngx-store] targets.length:  1
[ngx-store] currentTarget:
{initializeDefaultLayers: ƒ, storeLayers: ƒ, unique: ƒ, compareKeys: ƒ, ngOnDestroy: ƒ, …}
compareKeys
:
ƒ (key1, key2)
configurable
:
true
initializeDefaultLayers
:
ƒ ()
ngOnDestroy
:
ƒ ()
storeLayers
:
ƒ ()
unique
:
ƒ (layers)
activeOverlayKeys
:
(...)
constructor
:
ƒ LayersService(http, mapService, resourcesService, osmUserService, wikiMarkersLayer, nakebMarkerLayer, categoriesLayersFactory, poiService)
selectedBaseLayerKey
:
(...)
storedBaseLayers
:
(...)
storedOverlays
:
(...)
get activeOverlayKeys
:
ƒ ()
set activeOverlayKeys
:
ƒ (value)
get selectedBaseLayerKey
:
ƒ ()
set selectedBaseLayerKey
:
ƒ (value)
get storedBaseLayers
:
ƒ ()
set storedBaseLayers
:
ƒ (value)
get storedOverlays
:
ƒ ()
set storedOverlays
:
ƒ (value)
__proto__
:
Object
HarelM commented 7 years ago

I'm looking into the following method:

    CacheItem.prototype.getProxy = function (value, config) {
        if (config === void 0) { config = {}; }
        if (value === undefined && this.proxy)
            return this.proxy; // return cached proxy if value hasn't changed
        value = (value === undefined) ? this.readValue(config) : value;
        if (typeof value !== 'object' || value === null) {
            this.proxy = value;
            return value;
        }
        if ((!Config.mutateObjects && !config.mutate) || config.mutate === false)
            return value;
        var _self = this; // alias to use in standard function expressions
        var prototype = Object.assign(new value.constructor(), value.__proto__);
        prototype.save = function () {
            _self.saveValue(value, config);
        };
        // TODO set prototype for Array.prototype or something
        if (Array.isArray(value)) {
            var methodsToOverwrite = [
                'pop', 'push', 'reverse', 'shift', 'unshift',
                'filter', 'forEach', 'map', 'fill', 'sort', 'copyWithin'
            ];
            var _loop_1 = function (method) {
                prototype[method] = function () {
                    var value = _self.readValue(config);
                    var result = Array.prototype[method].apply(value, arguments);
                    debug.log('Saving value for ' + this.key + ' by method ' + prototype.constructor.name + '.' + method);
                    _self.saveValue(value, config);
                    return result;
                };
            };
            for (var _i = 0, methodsToOverwrite_1 = methodsToOverwrite; _i < methodsToOverwrite_1.length; _i++) {
                var method = methodsToOverwrite_1[_i];
                _loop_1(method);
            }
        }
        Object.setPrototypeOf(value, prototype);
        this.proxy = value;
        return value;

The above line looks suspicious to me: this.proxy = value; as it doesn't use _self - is this a mistake or it should be like that?

HarelM commented 7 years ago

Missed the last line of log for save, sorry: [ngx-store] initial value for activeOverlayKeys in LayersService []

DanielKucal commented 7 years ago

_self is only to use in standard function expressions (function() {}) to have the right scope

HarelM commented 7 years ago

Anything else I can check? print? debug?

DanielKucal commented 7 years ago

You said you have it available online, right? I could check it

DanielKucal commented 7 years ago

Please also try changing line number 101 in node_modules/ngx-store/dist/src/decorator/cache-item.js to return value || _this.proxy; in your project...

HarelM commented 7 years ago

The problem is that the online version in the site it self is minified so I think it will be hard for you to check. You best bet is maybe to try and run the code from the repository locally. In case you want to reproduce the error on the production site: Surf to https://israelhiking.osm.org.il/#!/?s=2QKnKT5g1N In case you want to reproduce it locally you can:

  1. Change language of the site to english: right side language button -> click English in the dialog.
  2. Click on the left layers button
  3. Click on the toggle button at the top to activate advance settings
  4. Click on add overlay
  5. enter some data and press OK -> error should appear, I think...
HarelM commented 7 years ago

Your line of code seems to solve the error. Not sure if this is the right fix or a workaround, but I'll take it :-)

DanielKucal commented 7 years ago

Oh great! Thanks for checking it, I have to apply that fix in this project

HarelM commented 7 years ago

Thanks for the interactive debug session!! Let me know when a new npm package is available.

DanielKucal commented 7 years ago

Well, that was fun! v1.1.8 released