Why angularjs throw 'Illegal invocation' when using promise construction? - angularjs

I invoke some promise function:
return $http.post("anyCtrl").then(location.reload);
After that I have thrown exception in browser console 'Illegal invocation' in angular.
If I invoke:
return $http.post("anyCtrl").then(function(){location.reload()});
Everything is good.
I expected that all of my code snippets should be working.

Passing location.reload as an argument works more or less the same as reassigning it. If you reassign an object's method and it's not bound, that object's this will become the object that it's assigned to. For example:
const notlocation = {};
notlocation.reload = location.reload();
notlocation.reload(); // illegal invocation
You need to invoke reload from the location object. There are a couple of ways you can do this. One is to have the parentheses with the method call explicitly as you've done:
$http.post("anyCtrl").then(() => location.reload());
Another is to use the .bind and bind it to the object you want to invoke the method:
$http.post("anyCtrl").then(location.reload.bind(location));

Related

AngularJS $window.open throws "Cannot read property 'arguments' of null"

I'm creating a simple web page where i display a button which execute this code
$window.open(link, "_self");
The link variable is a simple telegram link for a channel, but this is not the problem, the problem, as the question say itself, is about arguments variable in $window.open.
This in my opinion is strange because when i logged in the console $window.open function, i received this output:
function pbWindowOpen() {
lastBlockCaller = {
caller: arguments.callee.caller,
args: arguments.callee.caller.arguments
};
try {
return newWindowOpenFn.apply(this, argument…
At this point, should not i see an argument variable inside this function? How could i solve this problem?
Passing some arguments could resolve my problem? If yes, there's an answer about why i'm having arguments null?
I've also tried with window.open but nothing changes, always the same problem
That shouldn't happen if you are running your code in a browser (in other env you may have some initialized variable window representing something else), $window is a wrapper in top of var currWindow = $window.self || $window.window and then do a perform of callong open(...) function. Hence, you neither using the native javascript code badly in a angular context, and again that would be easily mock-ableif we mock $window and create a property call self or window inside it. So it will work in the application, and will also be testable.

Remove $promise and $resolved from json object not working

I'm getting data from the server using $resource like this
service
.factory('rulesService', ['$resource', function ($resource) {
var systems = $resource('url');
return systems;
}]);
controller
$scope.rules= rulesService.query();
console.log($scope.rules);
The output I get is
0: Resource
1: Resource
$promise: Promise
$resolved: true
length: 2
I tried to strip $promise & $resolved using
1) angular.toJson($scope.rules)
2)JSON.stringify($scope.rules, null, 2)
Both these are returning []
Can someone help me on this
After reading your comments above, I think your problem is you use $resource wrong.
$resource will return a empty object or array, and then make the http call in the background and populate the array/object once it is complete.
This means that, at the time you console.log the object, it is actually an empty array, but since the log in the browser is pretty smart, it will update the object in the log as well, once the $resource call is done.
this is why console.log(rules[0]) is undefined, while console.log(rules) says the element exists. It didn't at the time of the log.
If you need to do further processing you have to do something like:
var rules = rulesService.query(function () {
console.log(rules[0])
})
you can also use promises instead of a callback, but either way you need to ensure the data is fully loaded
You should be able to simply iterate over the array (and ignore the extra properties). If you want a clean array you could always use a map or similar.
$scope.new_rules = $scope.rules.map(function (rule){
return rule;
})
Your problem is related to asynchronous execution and race conditions.
You're trying to refer to rules[0] before data actually arrives from the $resource.query() call.
Examples:
var rules = rulesService.query();
console.log(rules[0]); //will print nothing. the GET request hasn't been resolved yet.
rules.$promise.then(function (response) {
console.log(rules[0]); //This WILL work assuming you actually get data from the backend.
console.log(response[0]); //This will also work with the same data.
});

In AngularJS, is there any side effect if you use module.service() when module.factory() should be used?

I saw some code in the existing code base:
angular.module("myApp", [])
.service("myService", function() {
return {
getData: function() { } // etc ...
};
});
I think the concept is this: if it is module.factory(), you provide a function to return an object (which is the service object), versus, if it is module.service(), you provide a function, which is in fact just a constructor function, so that later on, a new keyword will be used with this constructor function to obtain the service object.
However, the code above surprisingly actually works. It apparently is due to the fact that, if it is taken to be a constructor function (even though it is not), when the new keyword is used with it, it returns an object, so this object is return instead of the object instantiated with the new keyword. But the fact is, it still works.
So is it true that even when we should use module.factory(), using module.service() actually works. Is there any side effect?
I think it is best to be changed back to module.factory(), but at the same time, I am afraid if everything works now, changing it back to module.factory() may introduce new bugs.

Value in view not updating after $promise is resolved

I have a value in my view that is not updating after a service method is called.
Here is the relevant code in the controller:
$scope.remaining = 20;
AcctService.getCurrentCount.get(calculateRemaining); //This is a $resource method
function calculateRemaining(result) {
$scope.remaining -= result;
alert($scope.remaining);
}
Here is the code for .getCurrentCount:
service.getCurrentCount = $resource('/api/getCount', {}, {
'get': { method: 'GET', isArray: true }
});
With the above code, say for example the result returned is 5. "15" will be alerted. However, in the view, {{remaining}} is still 20. No errors, the view just doesn't update.
I have tried the following:
$timeout - nothing different happens
Making $scope.remaining an object with property "value". (I read in another post about issues with data binding of primitives vs references). No difference.
$promise and .then() - no difference
$apply results in a digest error
Note, I am also coding with Ionic, not sure if it makes a difference. I disabled caching in the Ionic config, and another service method that returns an array propagates an ng-repeat as expected.
Thanks!
I'm not sure what things look like inside that get() function, but it doesn't look right.
Assuming get() returns a promise, you should write it like this:
AcctService.getCurrentCount.get().then(calculateRemaining); //This is a $resource method
First of all you do not need to create get method to return array. Use default 'query' method of $resource. And first parameter for the method is an object of parameters. second one is success function. So change you service to this
service.getCurrentCount = $resource('/api/getCount');
And later use it as
AcctService.getCurrentCount.query({},calculateRemaining);
Also check if you are not using one way data binding {{::remaining}}
And also you have to make sure you are using right $scope, to check that make "remaining" a field of an object. You can do it this way:
$scope.myData = {};
$scope.myData.remaining = 20;
and later at the controller initialize it the same and at the html
{{myData.remaining}}
also you can use $scope.apply(); but actually that is used at different case

Why doesn't UnderscoreJS's _.extend() method copy AngularJS promises to the extended object?

Example:
$scope.post = Posts.get({id: id});
scope = _.extend({}, $scope);
alert($scope.post.id); // undefined
alert(scope.post.id); // exception - post is not defined
I feel that I'm doing something obviously wrong, but I can't figure out what. I expected it to shallowly copy the post reference to the new object:
alert($scope.post.id); // undefined
alert(scope.post.id); // undefined
$scope.post === scope.post; // true
This is from Angular documentation about ngResource
It is important to realize that invoking a $resource object method
immediately returns an empty reference (object or array depending on
isArray). Once the data is returned from the server the existing
reference is populated with the actual data. This is a useful trick
since usually the resource is assigned to a model which is then
rendered by the view. Having an empty object results in no rendering,
once the data arrives from the server then the object is populated
with the data and the view automatically re-renders itself showing the
new data. This means that in most cases one never has to write a
callback function for the action methods.
At the time when you are trying to extend the scope, your object is not fully there.
I hope that helps...

Resources