update original object with values from server after ajax post - javascript

I make a call to server and save some stuff, after successfull save I need to update the json array object I have with new values. Here is some of my code
[
{
"id": 1,
"uuid": "ce54acea-db20-4716-bceb-2f3deb1b2b86",
"name": null,
"order": 1,
"children": []
}
]
I got an array of object, they can be nested inside each other as well.
After I edit a specific object I can chose to save the new values to the server. After Save button is pressed and before I send data to server I store a reference to the object being edited. I store this refefence inside
selectNode = function(clickedNode) {
this.selectedNode = clickedNode
this.tempNode = _.clone(clickedNode)
}
I have a temp object here because the user can press Cancel button as well and that means any changes need to be discared as well. So I make a reference to the object being edited and then make tempNode object which I actually edit and upon Save push to server.
My problem is that after the successfull save I would like to update all values inside the reference object as well.
Right above I have just few values, but in my app every node will be have lots of values so I do not want to be doing this
this.http
.put("/api/manage/v1/"+this.tempNode.uuid, this.tempNode)
.map(res => res.json())
.subscribe((data) => {
this.selectedNode.name = this.tempNode.name
this.selectedNode.order = this.tempNode.order
... and so on, this list could get long and not manageable after while
}, (error) => {
console.log(error)
}
);
I also tried to do this in the same place replacing the above with
this.selectedNode = _.merge({}, this.selectedNode, this.tempNode);
but this destroys the reference and creates new object so the original object inside a json array never gets updated and ofc nothing gets then updated on the screen either.
Is there a way to automate this
this.selectedNode.name = this.tempNode.name
this.selectedNode.order = this.tempNode.order
this.selectedNode.etc= this.tempNode.etc
this.selectedNode.etc= this.tempNode.etc7
to one line of code where all values get copied to referenced object without destroying the reference with new object?

If you want to keep the reference, you can use standard Object.assign to assign all properties of tempNode to selectedNode without reassigning selectedNode:
.subscribe((data) => {
Object.assign(this.selectedNode, this.tempNode);
Object.assign (and _.merge, presumably) mutates the first argument, and you want mutation, not reassignment.

Related

How to query the list in a better way using AngularFireDatabase?

"#angular/fire": "^5.2.3",
I am using AngularFireDatabase to manipulate data in firebase. I need to retrieve and update the table below in Firebase. I am currently doing it in the below method. Is there any way which I can use it to query better? Because, I am downloading the entire table and then uploading it again. I don't want to download the entire list of submissions instead just want to push an object to the submission array directly. Thanks in advance.
// Get form submissions for a specific form
getFormSubmissions(key: string) {
this.userSubmissionsList = this.db.list('/form-submissions', ref => ref.orderByChild('formId').equalTo(key));
return this.userSubmissionsList;
}
getSingleFormForSubmission(key: string) {
this.submission = this.db.object('/form-submissions/' + key);
return this.submission;
}
this.formService.getFormSubmissions(this.formId).snapshotChanges().subscribe(response => {
let key = null;
response.forEach(item => {
const a: any = item.payload.toJSON();
key = item.key;
});
this.formService.getSingleFormForSubmission(key).valueChanges().subscribe(resp => {
if (resp.submission === undefined) { resp.submission = []; }
this.formSubs = resp;
});
});
Pushing the data be like:
this.formSubs.submission.push(data);
this.formService.submitUserValues(this.formSubs);
You're storing a JavaScript array in Firebase, which unfortunately means it becomes hard to manipulate. To add an item to an array, you must know how many items already exist in that array, which requires that you first read it.
This is one of the many reasons why the Firebase documentation recommends against using arrays, but instead uses so-called push IDs to add items to lists. From that documentation:
Use the push() method to append data to a list in multiuser applications. The push() method generates a unique key every time a new child is added to the specified Firebase reference. By using these auto-generated keys for each new element in the list, several clients can add children to the same location at the same time without write conflicts. The unique key generated by push() is based on a timestamp, so list items are automatically ordered chronologically.
I also recommend checking out this old-but-still-very-true blog post Best Practices: Arrays in Firebase.

How to merge 2 objects that contain an array of objects each?

I have an observable that gets data from an API, this is hooked up to a paginating feature. How do I add the response data object on to the variable which holds the first pages data. Essentially what Array push does.
Right now each pagination will send a request to the API, even the previous pages since I am overwriting the data. I would like to add the array of objects (data.articles) on to the end of the category that is selected.
data = {
general: undefined,
business: undefined,
entertainment: undefined,
health: undefined,
science: undefined,
sports: undefined,
technology: undefined
};
this.newsService.getNews(endpoint, params).subscribe(data => {
this.data[category] = data.articles;
});
I expect the data to work like this:
If i show 1 article on the general tab, data.general will hold an array with one object in it. When i click next page, data.general should hold an array with 2 objects in it, and so on.
Solution
Array.prototype.push worked, for some reason when i initially tried this it didn't work. But i think that was because it was undefined initially. The below however works fine.
if (!this.data[category]) {
this.data[category] = data.articles;
} else {
Array.prototype.push.apply(this.data[category], data.articles);
}
Try this, maybe this is what you want.
Array.prototype.push.apply(this.data[category], data.articles);
Above code will merge to array of objects into one and set to this.data[category]
I know you have already accepted an answer, but if you were interested in retaining the data in streams instead of in arrays, you can do something like this:
// Action Stream
private productInsertedSubject = new Subject<Product>();
productInsertedAction$ = this.productInsertedSubject.asObservable();
// Merge the streams
productsWithAdd$ = merge(
this.products$, // Original stream of data
this.productInsertedAction$ // New data
)
.pipe(
scan((acc: Product[], value: Product) => [...acc, value]),
catchError(err => {
console.error(err);
return throwError(err);
})
);
And if you were adding an array instead of a single value, the technique would be similar.

How do I properly push JSON array onto existing data array in Vue JS on a Axios response?

I think this is a general Javascipt question however I am working in Vue Js, Laravel & Axios.
How do I push one JSON array into another JSON array? My problem is that when I push the secondary array into the primary array it is nested (see screenshot). I need it as part of the same array.
Is this a simple index issue? I've read concat can achieve this, but I have a "load more" button and wish to append the array and increase the size from the bottom, so push is appropriate. concat creates a new array and replaces current, which isn't desired as I want to maintain the existing array and just increase size for smoother loading of results, like on Pinterest scroll and the new results populated at the bottom.
(this is simplified code to get point across)
Data property empty array to start:
data () {
return {
articles: [],
}
},
Firstly, on page load the articles array is populated with JSON data.
created() {
axios.get(url)
.then(response => {
this.articles = response.data.data;
});
},
Then, I want to 'load more' results via method
loadMore() {
axios.get(url)
.then(response => {
console.log('article\'s array data')
console.log(this.articles)
this.articles.push(response.data.data)
console.log('new response array data')
console.log(response.data.data)
console.log('the updated array with pushed response array')
console.log(this.articles)
});
}
console log
This should be an array of 5 + 5 = 10 for length of articles array if properly appended.
both responses are correct and matching json as I've got it working via concat to merge. But undesirable as it reloads entire array.
If you are against .concat, which is super a very straightforward and performant way, you may try the following:
const myArray = [1,3,4,5];
myArray.push(...[6,7,8,9);
console.log(myArray); // this will contain [1,2,3,4,5,6,7,8,9] now
Taken from advice from both #noa-dev and #Shilly above - I used concat as below. Response had to be set in a var for promise as didn't work without. Thanks.
var new_array = response.data.data
this.articles = this.articles.concat(new_array)
Explanation how Vue doesn't actually replace the array when using concat! :) https://v2.vuejs.org/v2/guide/list.html#Replacing-an-Array

unable to view new table data after concat - Ionic 3 Angular 4

I'm using ionic's events to pass data from page to page. In this instance I'm passing an array to another page, let's say with two objects. The data I'm wanting to add to is called dataOne and I'm using a life cycle function so that when the user enters the page they will be automatically tested from this function whether or not there is an event to be concatenated onto dataOne. The issue is, the data isn't being added. I'm able to retrieve the data but nothing happens to the table, as I'm still getting the same result.
ts
ionViewWillEnter(){
this.events.subscribe('market', (dataTwo) => {
return this.dataOne = this.dataOne.concat(dataTwo)
})
}
What is 'Market' ? dataOne is array? In my opinion,
dataOne: any[]=[];
...
this.events.subscribe((dataTwo) =>{
this.dataOne.push(dataTwo.market); // if market you want to catch data
}

What is the benefit of angular.copy?

I use angular.copy in some cases, like copying model default values to the form model, like this:
var customerModel = {
name: '',
point: 0
};
$scope.customer = angular.copy(customerModel);
function save() {
//... Reset $scope.customer after success submit
$scope.customer = angular.copy(customerModel);
}
... to prevent the default customerModel changed.
But why copy empty object or array? {} or []
I found in some codes used angular.copy on empty object or array. Why they don't assign empty object directly to the variable?
$scope.customer = {}; // or [] for array
If you use copy on empty object or array, could you explain the benefit?
What about ajax response ($http)?
And one more question, what did you do to ajax response? copy or assign it directly to a variable?
$http
.get('example.com/api/v1/get/customer/1')
.success(function(response) {
$scope.customer = angular.copy(response.data);
// or do you use $scope.customer = response.data ?
})
;
And if you used copy, what do you think happened to the response object?
Is it remain in the memory? or deleted automatically?
You copy an object to prevent other code from modifying it. (original object might change, but your copy won't see the changes)
If you were to do this:
$scope.customer = customerModel
... and some callback/service/whatnot changed customerModel, your scope would reflect this change. This is not always desirable, hence the need for deep copying.
Copying empty literal object
$scope.customer = angular.copy({})
// or
$scope.customer = {}
This doesn't make any difference. It's a new empty object every time. Note that it's very different from this:
this.customerModel = {};
$scope.customer = angular.copy(this.customerModel)
Copying ajax response data
Same rules apply. If you want to ensure that this object doesn't change from underneath you (which may happen if you also passed it to somewhere else, for example), you should copy it.
angular.copy creates deep copy of variable so that it would hold the reference of another variable
sometimes it happens when user dont want to use call by reference then deep copy comes in action According to your question
var customerModel = {
name: '',
point: 0
};
If you will use $scope.customer = angular.copy(customerModel); it will create deep copy of customerModel
As far as $http Service is concerned .Data is coming from response and If you you will assign It directly then there would be no effect of call by reference because data is coming from another source.
So I would rather assign it directly in case of $http.get()

Categories