If you have two c.server.updates inside one function why does it call server at the end of function twice?

Freddieoboy
Kilo Contributor

Kingston.

I created a widget that calls the server twice and I noticed an unexpected result.

You would think it would print out Hello World, but it prints out World World. 

Can anyone explain to me why this is occurring and how it would be possible

to print Hello World calling the server in this manner?

 

-------------------HTML------------------

<input type="button" onclick="first()">

--------------Client Script----------------

first = function() {
c.data.variable = "Hello ";
c.server.update();
callme();
}

callme = function() {
c.data.variable = "World";
c.server.update();
}

-----------Server Script---------------

if(input) {
gs.addInfoMessage(input.variable);
}
1 ACCEPTED SOLUTION

Oleg
Mega Sage

I found the question interesting. So I reproduced the test and debugged the client-side code carefully. As the result I can exactly explain the reason of problem and I can suggest the workaround.

The reason of the problem: c.server.update() calls internally $http with the reference on $scope.data (c.data) as a parameter. The method $http processes the send request not immediately. Instead of that $http creates a promise using $q.when forwarding parameters to promise. As the result, the reference to $scope.data (c.data) will be forwarded to the promise and the request will be processed later. The code of Client Controller of the demo changes variable property of c.data (c.data.variable) immediately after the call of c.server.update(). Thus, during processing of the request inside of internal serverRequest and sendReq functions of $http, one will use already modified $scope.data (c.data) object with the latest value of c.data.variable.

As the workaround I'd suggest to use c.server.get method instead of c.server.update:

//--------------Client Script----------------

var callme = function () {
	c.server.get({ variable: "World" });
};

$window.first = function () {
	c.server.get({variable: "Hello "});
	callme();
};
 

Personally, I use almost always c.server.get instead of c.server.update because c.server.update is just a wrapper to spUtil.get($scope, $scope.data) and c.server.get uses spUtil.get($scope, data) with data, which you specify explicitly. One should still be carefully in the usage objects as parameters of c.server.get. I stopped usage of c.server.update after I found, that the data previously returned from the server will be send to the server back on call of c.server.update. If you return an array of data on initial loading of page, then c.server.update could be much more slowly because of sending of unneeded data. So to use c.server.update one has to clear unneeded data from c.data, which can have other side effects if you use the data on the Body HTML Template or other ng-templates. The usage of c.server.get makes the code easier. Because of that I recommend to use c.server.get, which the only disadvantage is the name. I mean that c.server.get makes HTTP POST request to the server and not HTTP GET, which one can suppose from the name.

View solution in original post

8 REPLIES 8

Oleg
Mega Sage

I found the question interesting. So I reproduced the test and debugged the client-side code carefully. As the result I can exactly explain the reason of problem and I can suggest the workaround.

The reason of the problem: c.server.update() calls internally $http with the reference on $scope.data (c.data) as a parameter. The method $http processes the send request not immediately. Instead of that $http creates a promise using $q.when forwarding parameters to promise. As the result, the reference to $scope.data (c.data) will be forwarded to the promise and the request will be processed later. The code of Client Controller of the demo changes variable property of c.data (c.data.variable) immediately after the call of c.server.update(). Thus, during processing of the request inside of internal serverRequest and sendReq functions of $http, one will use already modified $scope.data (c.data) object with the latest value of c.data.variable.

As the workaround I'd suggest to use c.server.get method instead of c.server.update:

//--------------Client Script----------------

var callme = function () {
	c.server.get({ variable: "World" });
};

$window.first = function () {
	c.server.get({variable: "Hello "});
	callme();
};
 

Personally, I use almost always c.server.get instead of c.server.update because c.server.update is just a wrapper to spUtil.get($scope, $scope.data) and c.server.get uses spUtil.get($scope, data) with data, which you specify explicitly. One should still be carefully in the usage objects as parameters of c.server.get. I stopped usage of c.server.update after I found, that the data previously returned from the server will be send to the server back on call of c.server.update. If you return an array of data on initial loading of page, then c.server.update could be much more slowly because of sending of unneeded data. So to use c.server.update one has to clear unneeded data from c.data, which can have other side effects if you use the data on the Body HTML Template or other ng-templates. The usage of c.server.get makes the code easier. Because of that I recommend to use c.server.get, which the only disadvantage is the name. I mean that c.server.get makes HTTP POST request to the server and not HTTP GET, which one can suppose from the name.

Freddieoboy
Kilo Contributor

Ayyyeee! I am glad you enjoyed the challenge and I really appreciate your answer. I now have a great understanding of why it does what is does and a great workaround. I do still have one question though.

Suppose I want to use all the current c.data information. Is there a way to do that?

You are welcome! I'm not sure that I understand you correctly. If you want to use full c.data then you can use c.server.get(c.data); or better use the copy of c.data:

c.server.get(angular.copy(c.data));

or

c.server.get($.extend({}, c.data));

or

c.server.get($.extend(true, {}, c.data));

to make deep copy of c.data object in new object. I don't want to go in details of different methods, which can be used to make a copy of object (angular.copy, angular.extend, angular.merge, jQuery.extend and so on). You can use some other constructs like JSON.parse(JSON.stringify(c.data)) for example. If you have more interest about that you can find the corresponding information in Internet. For example, this article. Important would be just to make a copy of c.data instead of using a reference.

Freddieoboy
Kilo Contributor

ahh okay. I was just curious because when I do a server update I can access all my c.data but it seems that when I use a server get call, it seems that I can not access all of my c.data. Thats why I asked