Get dynamic scope array variable value in angularjs - arrays

I have a scope array variable which i am trying to access dynamically. Its value has been already set.
Its like this.
$scope.setp = { arr: [] };
$scope.setp.arr[0] = "sample Value";
When I am trying to access it dynamically as below I get undefined.
console.log($scope['setp.arr[0]']);
However I am able to access it directly using the following.
console.log($scope.setp.arr[0]);
The way of dynamically getting value of scope variable works fine for others but fails when the variable name contains square brackets i.e. [ ].
I followed this example but no success for scope variable containing array or square brackets [ ].
Also dynamically setting of scope array variable using $parse service works fine as in below.
var scopeVariable = $parse('setp.arr[0]');
scopeVariable.assign($scope, "new Value");

This won't work console.log($scope['setp.arr[0]']); as its trying to access a property setp.arr[0]. You can access it like console.log($scope['setp']['arr'][0]);

Related

TypeScript Variable Undefined inside array.forEach()

I will try to explain my problem. I have an array of a particular object and, from this array, I want to create a new one with the value of a particular field of each object.
In order to achieve this, I tried to use array.forEach() method but I get a variable undefined error inside the forEach() function. This is my code:
var values: number[];
measures.forEach((measure)=>{
values.push(measure.value);
});
I've tried to declare the array values as public (and access this.values) and also to declare it in the function where I make the forEach and neither way worked.
Here is the error I get in the browser (angular CLI reports no problem):
ERROR TypeError: "values is undefined"
Try to initialize your array rather than just declare it as
values: number[] = [];
You do not need the var keyword in angular if you are declaring a variable directly inside a component class. If you need to do it inside a function, use let keyword. more information HERE

Can't directly assign new array instance to existing array from method

Issue is demonstrated in this plunker:
https://plnkr.co/edit/h1fFuY9VOZDLHO5JAM3o
I know that all arrays in Typescript are passed by reference. Thus it should be possible to assign new array to this reference.
But I've got a problem. If I want to replace one array with another from inside of the method in Angular 6.1.7 (TS 2.9.2), changes are not visible from outside of the method.
private assignArray(arrayToReplace: any[], replacement: any[]) {
arrayToReplace = replacement;
}
I've found workaround to this problem. Instead of assigning source array to target array, I remove all entries from target array and push all entries of source array in it.
private replaceArray(arrayToReplace: any[], replacement: any[]) {
arrayToReplace.splice(0, arrayToReplace.length);
for(let c of replacement) {
arrayToReplace.push(c);
}
}
Actually, this plunker behaves strange because console shows that array was changed even before invocation of replaceArray() method.
So it this behavior a bug of Angular/Typescript?
You are right that array is passed by reference, but you get the copy of the reference in your method. So when you modify the reference you modify its copy. There are no modifiers like out or ref that could help you. I suggest you return the new array that you try to return via a parameter.

Why array in $scope doesn't updated using array concat method?

When I use concat method, my $scope is not updated
var anotherList = ["2", "3", "4"];
$scope.list = [];
$scope.list.concat(anotherList);
But using array push method in a loop, my $scope gets updated
Your syntax is wrong. You need to assign the return value of .concat() to your scoped array.
$scope.list = $scope.list.concat(anotherList);
Alternatively, if you used call() you could bind the result directly to the scoped array without the need to "reassign" since it would be done under the hood for you.
$scope.list.concat.call(anotherList);
See the documentation.
What David said is correct. Just to add: concat() doesn't modify the array, it just return a new array based on the parameters received. Check this for more info:
http://www.w3schools.com/jsref/jsref_concat_string.asp
If you want to maintain the original array, instead of concat you can do:
Array.prototype.push.apply($scope.list, anotherList);

Access $scope object with protractor

I got an object like:
$scope.project = {name: 'whatever', description: 'blabla', another: 'another'};
To debug this, I enter in repl mode and try to see what "project" has.
When I define project variable as below, and call it, it returns my object, but when I try to access its keys (project.name), I get undefined. If I do Object.keys(project) I am getting the page object methods like click, getAttribute, etc.
Any ideas on how can I have access to the original object keys?
View side:
<h1 id="foo">{{project.name}}</h1>
Test side:
var project = element(by.id('foo')).evaluate('project');
evaluate uses executeScript behind the scenes. It returns an ElementFinder which resolves to the object you are looking for:
var project;
element(by.id('foo')).evaluate('project').then(function(value) {
project = value;
});
The documentation says:
which resolves to the evaluated expression for each underlying
element. The result will be resolved as in
webdriver.WebDriver.executeScript. In summary - primitives will be
resolved as is, functions will be converted to string, and elements
will be returned as a WebElement.
Also, check out Accessing Angular inside Protractor Test
Edit: syntax error

AngularJS evaluate an interpolation expression without printing to screen

I have an expensive function call that gets called once per loop, but I would like to set the return value of that to be a temporary variable that can be used directly within the loop.
This works by setting {{ val=fn(...) }}, but it also prints to the screen. Is it possible to do this without printing the value?
I've tried using one set of curly braces {} but it doesn't work.
Any ideas on how to do this?
Have you looked into "filters" or possibly doing the work in your JS code instead of the view?
Instead of a temporary variable, call a method when you need the value, and in this method, use a cached version of the result, or call your expensive method if the cached version is null/undefined. It will only call your expensive function once per iteration, and it won't call it if it's not needed. It won't print it unless you want to. Because each iteration of a ng-repeat spawns a new scope, each iteration will start with an empty cache.
e.g.:
$scope.cache = null
$scope.getValue = function() {
if (!this.cache) { // use typeof if 0 or false or empty string is valid!
this.cache = myExpensiveFunc()
}
return this.cache
}
Not 100% sure $scope.cache = null will be initialized for each scope of the iteration, you may need to check if 'this' hasOwnProperty 'cache' in getValue. So in your view, you only reference getValue() when you need to.
HTH!
edit: cache on scope, not in controller.

Resources