angular.fromJson not working properly - angularjs

The code is as follows
var taskString = window.localStorage['tasks'];
if(taskString) {
var tasks = angular.fromJson(taskString);
console.log(tasks);
}
I had a json format string stored in the window.localStorage['tasks'], which is like this
[{"title":"a"},{"title":"b"},{"title":"c"}]
so that the var taskString would be exactly [{"title":"a"},{"title":"b"},{"title":"c"}]
in the code I tried to parse this string into a json array tasks, and the array should contain three objects with the title attribute set separately as a, b and c
but the problem here is, after the execution of angular.fromJson(taskString), I print the array out to the console, and in the array the titles become b,c, and undefined
Is this a bug of that funciton? Or did I mistankenly do something I shouldn't have in my code?
Thanks

It seems to work fine. Look at the following example snippet. I emulated localStorage as storage.
Check for any silly mistakes or if you are setting it properly.
var storage = {
setItem: function(name, item) {
this[name] = item
}
}
storage.setItem('tasks', '[{"title":"a"},{"title":"b"},{"title":"c"}]')
var taskString = storage['tasks'];
if (taskString) {
var tasks = angular.fromJson(taskString);
console.log(tasks);
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

var json = '[{"title":"a"},{"title":"b"},{"title":"c"}]';
var obj = angular.fromJson(json);
console.log(obj);
Works fine for me, below is the fiddle:
http://jsfiddle.net/n8ezb7sg/89/

Related

push method in Array not working - Angular 2

I am stuck with this piece of code for last 4 hours, unable to figure out what's the issue. It's written in typescript.
the newsa array is to be filled with the data I've pulled using the api. but instead, it shows errors like can't find push property, after I declare the array properly with all needs like the public prefix and all. There is no error but nothing is getting pushed. What's wrong.
It would be great help if you answer.
public newsa: Array<any> = [];
fetchNews() {
console.log("Fetch NEws has started");
var that = this;
let googlenewsUrl:string;
let finalUrl: string;
this.countries.forEach(function(i) {
googlenewsUrl = "https://news.google.com/news?q=" + i.name.replace(/\s+/g, '') + "&output=rss";
finalUrl = '//ajax.googleapis.com/ajax/services/feed/load?v=1.0&num=50&callback=JSONP_CALLBACK&q=' + encodeURIComponent(googlenewsUrl);
that.jsonp.get(finalUrl).toPromise().then(news => that.newsa.push(news)).catch(that.handleError);
});
}
Instead of
function(i)
use
(i) =>
to retain the scope of this

iterate each object in array and populate each element of the array with result. asynchronously

I need help with array asynchronous iterate functionality. I working with node-opcua library in nodejs. There is function session.browse(nodeId, result)
Right now code looks like:
NodesTree = {
"NodesTree":{
"name":"SYM:",
"subf":[]
}
};
the_session.browse("ns=1;s=SYM:", function(err, browse_result){
if(!err) {
var buf = [];
browse_result[0].references.forEach(function(reference) {
if (reference1.browseName.namespaceIndex > 1) {
buf.push(reference);
}
});
NodesTree.subf = buf;
}
});
In result I get references of SYM: folder example:
[{"referenceTypeId":"ns=0;i=35","isForward":true,"nodeId":"ns=6;s=S71500ET200MP station_1","browseName":{"namespaceIndex":6,"name":"S71500ET200MP station_1"},"displayName":{"text":"S71500ET200MP station_1","locale":"en"},"nodeClass":"Object","typeDefinition":"ns=0;i=61"}]
I have Nodes structure in opc like this:
->SYM:
-->PLC
--->PLC_name
---->global_tag <variable>
---->global_tag1 <variable>
---->block
------>blok_tag1 <variable>
------>block_tag2 <variable>
Task is make one complete JSON object as tree for further use.
Logic is that: for each element in the references array get nodeId value and browse for references of the element and assign as element.subf = reference.
Final result something like:
NodesTree = {
"NodesTree":{
"name":"SYM:",
"subf":[
{attributes of PCL structure got by **browse**() + subf:[{ attributes of PLC_name by browse(), subf:
[{....and here again attributes and subf] }, {if no subf just assign subf; [] }]
]
}
};
So need call session.browse() for each reference and all finally bind to one object.
I tried to use Async library each and map in series functions to solve all that, but get nothing wise in result. May be there some smart solution can be found by Stack overflow community. Please help.
I am not familiar with node-opcua but assume that session.browse() is also async. Then something like this might work?
var async = require('async');
async.map(buf,
function(reference, callback) {
session.browse(reference.nodeId, function (err, result) {
callback(err, result);
});
}, function(err, results) {
// results is now an array of all single results
NodesTree.subf = results;
});

ngrepeat does not iterate $ attribute

I tried filtering with an object and to print out the filters via ng-repeat = (key, value) in object.
As I tried various filters, I saw that ng-repeat does not seem to work with the object's $ attribute, which is pretty useful if you are filtering.
Is there a possibility to show all attributes of the filtering objects automatically even if you use $
This link shows it doesn't seem to work with objects starting with $
$scope.testObj = {};
$scope.testObj.test = 'test';
$scope.testObj.$ = '$';
$scope.testObj.$test = '$test';
<div ng-repeat = "(key, value) in testObj">
<p>{{key}}: {{value}}</p>
</div>
AngularJS doesn't support it yet. There is an open issue on Github.
However you can make it work with a little code:
app.controller('MainCtrl', function($scope) {
var getProperties = function(input){
var result = [];
for(var propertyName in input) {
result.push({key : propertyName, value : input[propertyName]});
}
return result;
};
$scope.testObj = {};
$scope.testObj.test = 'test';
$scope.testObj.$ = '$';
$scope.testObj.$whatever = '$whatever';
$scope.testObjProperties = getProperties($scope.testObj);
});
Then display it in your view:
<div ng-repeat="property in testObjProperties">
<p>{{property.key}} : {{property.value}}</p>
</div>
Here's a working plunk : http://plnkr.co/edit/LFrfLcpoOg0ScEY89p25?p=preview
Looks like ng-repeat filters out object properties that begin with $.
This is from the source:
for (var itemKey in collection) {
if (collection.hasOwnProperty(itemKey) && itemKey.charAt(0) != '$') {
collectionKeys.push(itemKey);
}
}
This is most likely due to the fact that Angular uses $ to indicate code that is internal to the Angular library.
It seems this will only occur if you are using ng-repeat over an object.
I see them being disallowed specifically in the code:
https://github.com/angular/angular.js/blob/master/src/ng/directive/ngRepeat.js#L341
There are no comments around, and I agree this looks more than a bug than a feature, to me. Isn't that what marking properties as non-enumerable and Object.keys is for?
Browser compatibility hell, may be the reason, as always.

How to append a new value to an item within an array in Firebase?

Within Firebase, I have a list of 'ideas.' If a user presses a button associated with the idea, I'd like a value to be appended to that idea under an attribute called 'newValue.'
For example, the below html, uses ng-repeat to show the array of ideas and creates an associated button called 'Append Value.' I want a new value to be appended to the idea's attribute called 'newValue' every time a user presses 'Append Value.'
<body ng-controller="ctrl">
<table>
<tr class="item" ng-repeat="(id,item) in ideas">
<td>{{item.idea}}</td>
<td><input ng-model="newValue"></td>
<td><button ng-click="ValueAppend(id,newValue)">Append Value</button></td>
</tr>
</table>
</body>
Below is my attempt to create this function.
var app = angular.module("app", ["firebase"]);
app.factory("Ideas", ["$firebase", function($firebase) {
var Ref = new Firebase('https://crowdfluttr.firebaseio.com/');
var childRef = Ref.child('ideas');
return $firebase(childRef).$asArray();
}]);
app.controller("ctrl", ["$scope","Ideas", function($scope,Ideas) {
$scope.ideas = Ideas;
$scope.idea = "";
$scope.ValueAppend = function (id,newValue) {
var URL = "https://crowdfluttr.firebaseio.com/ideas/" + id + "newValue";
var IdeaRef = new Firebase(URL);
var IdeaData = $firebase(IdeaRef);
$scope.IdeaAttributes = IdeaData.$asArray();
$scope.IdeaAttributes.$add({
newValue: newValue,
timestamp: Date.now()
});
};
}]);
See my codepen for my working example: http://codepen.io/chriscruz/pen/PwZWKG
More Notes:
I understnad that AngularFire provides $add() and $save() to modify this array, but how could I use these methods so that I can add a new 'string' under an item in an array.
I'm not sure if these are your problems, but they are two typoes of mistakes in the code above and the codepen: typos and conceptual.
Typos
You forgot to inject $firebase into the controller, which leads to:
"ReferenceError: $firebase is not defined"
Solution is simply of course:
app.controller("ctrl", ["$scope","Ideas", "$firebase", function($scope,Ideas,$firebase) {
In addition you seem to be missing a slash before newValue, which means that you're trying to create a new idea instead of adding the value to an existing one. Solution is simple again, add a slash before newIdea as in:
var URL = "https://crowdfluttr.firebaseio.com/ideas/" + id + "/newValue";
If you find yourself making this mistake more often, you might be better server by the child function. Although it typically is a bit more code, it lends itself less to this typo of typo. Creating the ref to the newValue node becomes:
var URL = "https://crowdfluttr.firebaseio.com/ideas/";
var IdeaRef = new Firebase(URL).child(id).child("newValue");
Conceptual
With those trivial typos out of the way, we can focus on the real problem: which is easiest to see if you console.log the URL that you generate:
https://crowdfluttr.firebaseio.com/ideas/0/newValue
Yet if you look up the same data in the Firebase forge (by going to https://crowdfluttr.firebaseio.com/ideas/ in your browser), you'll see that the correct URL is:
https://crowdfluttr.firebaseio.com/ideas/-JbSSmv_rJufUKukdZ5c/newValue
That '0' that you're using comes from the id and it is the index of the idea in the AngularJS array. But it is not the key that Firebase uses for this idea. When AngularFire loads your data with $asArray it maps the Firebase keys to Angular indexes. We need to perform the reverse operation to write the new value to the idea: we need to map the array index (in id) back to the Firebase key. For that you can call [$keyAt(id)][1]. Since you keep the array of ideas in Ideas, it is simply:
var URL = "https://crowdfluttr.firebaseio.com/ideas/";
var IdeaRef = new Firebase(URL).child(Ideas.$keyAt(id)).child("newValue");
So the controller now becomes:
app.controller("ctrl", ["$scope","Ideas", function($scope,Ideas) {
$scope.ideas = Ideas;
$scope.idea = "";
$scope.ValueAppend = function (id,newValue) {
var URL = "https://crowdfluttr.firebaseio.com/ideas/";
var IdeaRef = new Firebase(URL).child(Ideas.$keyAt(id)).child("newValue");
var IdeaData = $firebase(IdeaRef);
$scope.IdeaAttributes = IdeaData.$asArray();
$scope.IdeaAttributes.$add({
newValue: newValue,
timestamp: Date.now()
});
};
}]);
I quickly gave it a spin in your codepen and this seems to work.

protractor return array of values from repeater

I am looking for an easy way to return an array of values from protractor's all.(by.repeater)
Basically, I just want an easy way to make an array of usernames given a repeater like user in users.
Right now I'm building it like this:
allUsers = element.all(by.repeater('user in users').column('user.username')).then(function(array){
var results = []
var elemLength = array.length
for(var n = 0; n < elemLength; n++){
array[n].getText().then(function(username){
results.push(username)
})
}
return results
});
expect(allUsers).toContain(newUser)
Is there a more concise, reusable way to do this built into protractor/jasmine that I just can't find?
AS alecxe said, use map to do this. This will return a deferred that will resolve with the values in an array, so if you have this:
var mappedVals = element.all(by.repeater('user in users').column('user.username')).map(function (elm) {
return elm.getText();
});
It will resolve like this:
mappedVals.then(function (textArr) {
// textArr will be an actual JS array of the text from each node in your repeater
});
I've successfully used map() for this before:
element.all(by.repeater('user in users').column('user.username')).map(function (elm) {
return elm.getText();
});
When I researched the topic I took the solution from:
protractor - how to get the result of an array of promises into another array

Resources