I've got a JSON array i'm loading from localstorage which I want to add more items to and put back in local storage. However, i'm getting a bit lost and an error saying concat doesn't exist.
$scope.searchObj = {
term: searchTerm
};
$scope.curObj = $scope.curObj.concat($scope.searchObj);
localStorage.setObject('searchObj', $scope.curObj);
$scope.curObj currently looks like:
Object {term: "fs"}
And I'd like to push the searchTerm (in searchObj) in to curObj so it looks like
{"term":"fs","term":"searchterm"}
$scope.searchObj is not an array but a JSON object.
You actually want to merge two objects. You can use in plain JS :
for (var attrname in $scope.curObj) {
$scope.searchObj[attrname] = $scope.curObj[attrname];
}
Or by using angular extend
$scope.searchObj = angular.extend($scope.searchObj, $scope.curObj);
Use ngStorage for storing object into localstorage and use service $localStorage -
Reference
Use angular.extend(oldobject,newobject) for merging
Related
Im building my first Django app.
I want to call a javascript function that receives a list of strings.
In my current version Im sending a Django object (called provider) property like this and it´s working fine:
<i class="fi-download"></i>
But now I want to call a Provider model method that returns a list of strings, so then I can do something with this list in Js method
def get_provider_files_urls(self):
provider_files = self.provider_files.all()
file_list = []
for f in provider_files:
file_list.append(f.file.name)
return file_list
I tried this:
<i class="fi-download"></i>
and got this error:
Uncaught SyntaxError: missing ) after argument list
A quick and dirty way to generate a JS array from a list is to use the join filter
onclick="download_provider_files(['{{ provider.get_provider_files_urls|join:"', '" }}'])"
Probably cleaner to use the json_script filter though
Ive looked related posts and couldn't quite find what I was looking for.
So I am build a backend rest api and I have certain tests I am collecting data on. The tests have their own models, and these models are associated with collections (obviously).
So I have a separate controller for each model. Now I have a "job" controller which queries data from each separate test. Now I have a separate script where I store these model objects in an JSON object. I am wondering how I can access these models properly (I am close but cant quite assign properly). Here is the block:
const testMappings = {
'aprobe':aprobe,
'status':status,
//'rxserial':rxserial,
}
Now when I try assignment as follows, where testMappings is the imported script variable:
const testMappings = activeTests.testMappings;
console.log(testMappings['aprobe']);
I get the following output:
Model {aprobe}
I would like to access the actual aprobe object. Also if anyone knows a better way of dynamically assigning these (instead of having bunch of if statements ie if(name == 'aprobe').... do something), it would be much appreciated.
You are probably looking for something like below :
const name = 'aprobe';
Object.keys(testMappings).indexOf(name) > -1 ? testMappings[name] : null
the above should give you: Model {aprobe}
So basically if the key exists in your object then you'd like to fetch the value of that key which would give you your model dynamically.
I use ng-prime <p-autocomplete> for display values via search in the back-end
here is my html
<p-autoComplete [(ngModel)]="agent" [suggestions]="filteredAgents" name="agents" (completeMethod)="filterAgents($event)" [size]="10"
placeholder="Agents" [minLength]="3"></p-autoComplete>
At the component.ts I initialize array like this at start of the component
filteredAgents: string[] = [];
and I have a method to send query to back end and push it to array
filterAgents(event) {
let query = event.query;
this._agentsService.getAgentSearch(query).subscribe(result => {
result.items.forEach((value) => {
this.filteredAgents.push(value.name);
console.log(this.filteredAgents);
});
});
}
I see filtered value in console, but I don't see it in suggestions.
Where can be my problem?
AutoComplete either uses setter based checking or ngDoCheck to realize if the suggestions has changed to update the UI. This is configured using the immutable property, when enabled (default) setter based detection is utilized so your changes such as adding or removing a record should always create a new array reference instead of manipulating an existing array as Angular does not trigger setters if the reference does not change. ( Angular documentation )
Array.prototype.push doesnt create a new reference it rather mutates the original array. So you need to make a new one.
filterAgents(event) {
let query = event.query;
this._agentsService.getAgentSearch(query).subscribe(result => {
this.filteredAgents = [...result.items.map(e => e.name)]
});
}
I maped the result to extract the names.
If filtered agents is an object array try adding field="name" to the directive attributes.
Here name is a field in the object. The directive uses this field to display in suggestions
GOOD SOLUTION HERE
In the case below I am trying to get data from one location and then find the related data in a different location (the firebase joins).
I am able to retrieve the appropriate data and display in the my console but I kind of stuck when it comes to storing them in one of my properties to then loop over them with a dom-repeat template. In addition I am not entirely sure if this should be done with plane JavaScript or the PolymerFire components.
//Key value for a course that I retrieved from a URL Query
var ckey = KSH456YU789;
//Get the Videos that belong to that course key
firebase.database().ref('/courseVideos/' + ckey).on('child_added', snap => {
//Get the video data of each video that belongs to the course
let videoRef = firebase.database().ref('videos/' + snap.key);
videoRef.once('value', function(snapShot) {
this.set('courseVidObj', snapShot.val());
//console.log() the data works
console.log(this.courseVidObj);
}.bind(this));
});
As it can be seen above I am able to log the data that is stored in my property 'courseVidData' which is from type Array. However, this is run for each request which basically overwrites the previous stored value.
This makes it impossible to use my property inside a dom-repeat template. As shown below:
<template is="dom-repeat" items="[[courseVidData]]" as="vid">
<my-card
card-img="[[vid.img]]"
card-name="[[vid.title]]"
card-text="[[vid.description]]"
card-key="[[vid.$key]]">
</my-card>
</template>
Second Attempt
In my second attempt I used a forEach() to store the returned data insie an array which I then added to my 'courseVidData' property.
This returns me as expected an array with three objects. Unfortunately the dom-repeat is doing nothing.
firebase.database().ref('/courseVideos/' + ckey).once('value', function(snap) {
var vidData = [];
snap.forEach(function(childSnapshot) {
let videoRef = firebase.database().ref('videos/' + childSnapshot.key);
videoRef.once('value', function(snapShot) {
vidData.push(snapShot.val());
this.courseVidData = vidData;
console.log(this.courseVidData); //returns array with the object's
}.bind(this));
});
});
So I found a way of doing it after reading through the documentation of the Polymer Template repeater (dom-repeat) And the way Arrays are handled in Polymer.
This might be not the cleanest approach but it works for now. If somebody is pointing out what could be improved I am happy to change my answer or accept a different one.
//Retrieve course videos and their details
firebase.database().ref('/courseVideos/' + ckey).on('child_added', snap => {
let videoRef = firebase.database().ref('videos/' + snap.key);
videoRef.once('value', function(snapShot) {
if (!this.courseVidData) this.set('courseVidData', []);
this.push('courseVidData', {video: snapShot.val()});
}.bind(this));
});
I can't really explain why but I had to add a if statement to check for the array and set it if not existing. Then I place the value of my snapshot inside the 'courseVidData' Property which is declared inside my Properties and from type Array.
Because the key of each returned object is now 'video' it is necessary to use [[item.video.title]] to access the object values (code below).
<template is="dom-repeat" items="[[courseVidData]]">
<h1>[[index]]</h1>
<h1>[[item.video.title]]</h1>
</template>
Update
Although this method works the unique key Firebase creates gets lost in the array. To keep the key for each object I store both key and object inside another object and append this to my array.
I know this isn't pretty and as mentioned above I am still looking for a better solution. However, it does the trick for me as a bloody beginner.
firebase.database().ref('/courseVideos/' + ckey).on('child_added', snap => {
let videoRef = firebase.database().ref('videos/' + snap.key);
videoRef.once('value', function(snapShot) {
var vidKeyObj = {key:snapShot.key, value:snapShot.val()};
if (!this.courseVidData) this.set('courseVidData', []);
this.push('courseVidData', {video: vidKeyObj});
}.bind(this));
I'm trying to write functions for storing and retrieving window state but cannot figure out how to do that. The idea is that user could make at any time a "snapshot" of the screen and with next login to the app he could retrieve it back, also he can store as many snapshots as he want.
For example: on the page I have 4 different closed panels with some kind of filters and 6 different tabs with grid inside (by default the first tab is opened). Now let's say, I have opened 2 of 4 panels, set some filters and worked with 5th tab. I want to be able to store whole window state (For example "My state 1"), and when I logged in at next time, just choose "My state 1" and get back my window state.
I already store and retrieve all grid properties in DB with next functions:
Store:
$scope.state = {}
$scope.saveStateString = function(store) {
$scope.state = JSON.stringify($scope.gridApi.saveState.save(store));
// console.log("function save state string")
};
Retrieve
if(objNode.folderId){
eventService.singleFilter(nodeId)
.then(function (res) {
if (res.body){
$scope.restoreStateString(JSON.parse(res.body));
}
});
}
else if (typeof objNode.folderId === "undefined"){
return false
}
$scope.restoreStateString = function(restore) {
$scope.gridApi.saveState.restore( $scope, restore );
};
For now I'm trying to store window state in localstorage and do next:
var storeValue = null;
var keyName = null;
var _window = {};
$scope.storeWorkspace = function (){
for (prop in window)
_window[prop] = window[prop];
storeValue = JSON.stringify(_window)
keyName = prompt("put your key name");
localStorage.setItem(keyName, storeValue);
};
but I get this error
angular.js:13708 TypeError: Converting circular structure to JSON
at Object.stringify (native)
I clearly understand, why I'm getting this error, it cause JSON doesn't accept circular objects - objects which reference themselves also I see from
console.log(_window) how the "window" has many objects inside, so I decided to ask:
How to store and retrieve window state?
Don't mix application data and resources to store, its huge, hard to reuse and will lead to running into other issues.
Keep it simple!
Construct appState object with what you required to reload the views
var appState ={config:{}, data:{}};
Store it in internalStorage / sessionStorage based on how long you to retain forever vs per session
localStorage.setItem("appState", appState);
On initial app start logic, load data from internalStorage / sessionStorage or server and you may modify existing controller code for binding it to the view.
getApplicationData(){
var appState = localStorage.getItem("appState");//get it from browser storage
if(!appState)
//get it from server
return appState;
}
This is more robust and performant approach.
The vast majority of values stored on the window object are simply not serializable. You will not be able to use JSON for this. You should instead track all changes you make to window and store those in a separate JSON object as POJOs. Alternatively, you can copy the initial window object when your application starts and then only store the differences between the current window object and the original copy.
In any case, this is probably going to be a hunt of trial and error, depending on what libraries you are using, and how they are using global variables. You will probably find you need to manually filter out some stuff when you serialize. Best practices would suggest nothing should write to the window object. If you have things writing to the window object, you're probably dealing with badly behaving code.
Do not try to store the whole window. Store your application's state in a separate object, e.g. state, which you can then attach to the global object if you absolutely have to:
window.state = {}; // your application's state goes here
var serializedState = JSON.stringify(window.state); // To be put into localStorage
Make sure that all the information you need to rebuild your app during the next launch is contained in this object, and nothing more than that. Avoid global state where possible.
Also make sure that your state object only contains serializable data. E.g. functions or symbols cannot be serialzied to a JSON string and will get lost in the process.