Accessing a variable in a nested Angular foreach loop using context - angularjs

I'm still brand new to Angular and Javascript, looked around for a solution to this but having a hard time finding one so please bear with me here. I have an Angular function that looks like this:
post: function(url, params) {
var someObject = {
'key': ['value1', 'value2']
}
for (var paramKey in params) {
angular.forEach(someObject, function (values, key) {
if (paramKey.indexOf(key) !== -1) {
debugger; // params is still defined here
angular.forEach(values, function (innerValue) {
if (paramKey.indexOf(innerValue) !== -1) {
debugger; // params is no longer defined
}
}, params)
}
}, params)
}
I want to iterate through some keys and values and based on what I find in the inner loop, I want to manipulate the params object before sending it to the API.
Looking at the forEach documentation, I can use the context argument to pass the object inside the forEach and keep it in scope. However, I'm using a nested loop, and for some reason it seems I can't keep passing params via context through into the nested loop. It just becomes undefined the second time.
How can I access and manipulate the params object in the inner loop?

Nesting loops is always best to be avoided, so I kind of thought, why do you even need to itterate if you are just checking the key of the object and then check if the key matches any of array strings. You can do the same thing like this:
post: (url, params) => {
var someObject = {
'key': ['value1', 'value2']
}
Object.values(params).forEach((paramKey) => {
if(someObject[paramKey]) {
if(someObject[paramKey].includes(paramKey)) {
}
}
})
}

Related

Superagent Not Returning Value From Then

superagent.get(URL).then((res) => {
for(let i in res.body) {
if (i==='has_rejected_advisories') {
console.log(i + "="+res.body[i]);
}
}
})
.catch((err) => err.message));
My result is:
has_rejected_advisories=false
But I am not able to use res.body[i] outside this function, i.e I want superagent function to return this value in a boolean variable to use it elsewhere.
ex.
a = superagent.get(URL).then((res) => {
for(let i in res.body) {
if(i==='has_rejected_advisories') {
console.log(i + "="+res.body[i]);
}
}
})
.catch((err) => err.message));
if(a===false){/*do this*/}
This is because the superagent.get(url) call is asynchronous. The value given to a is a Promise
Since this is async, the if (a === false) is actually executing before the function body passed to .then. You will either need to move this logic to the .then function, or use something like async/await if you like the synchronous looking syntax.
On top of jerelmiller's great advice you need to note the following:
Try this:
create a global var assuming it's a string
var mysares = ""
This example will only bring back 1 string back of everything!! Not single element. Also if you can't get the standard Fetch() to work don't try other methods like axios or superagents. Now use our global like so:
superagent.get(URL).then((res) => {
for(let i in res.body) {
if (i==='has_rejected_advisories') {
//Add comments as will help you
//to explain to yourself and others
//what you're trying to do
//That said if this iteration produces
//correct data then you're fine
//push my result as a string
mysares = res.body[i];
//infact what's in row 1?
mysares = res.body[0];
//Actually I code my own JSON!!
mysares = res.body[1];
console.log(i + "="+mysares);
}
}
})
.catch((err) => err.message));
Now you can do whatever:
if(mysares===false){/*do this*/
alert(playDuckHunt());}
Things to note:
res.body[i] is an iteration
You cannot use it outside of the function
Because:
It's local to that function
You don't know what position of 'i' is even if you could use it as you will be outside of your loop
One last thing:
Loops loop through loops or arrays etc.
So (in real world) you can't just request the value of the loop
unless you agree the position of data to be released,
type,and bucket (where it's going to be displayed or not).
Hope this helps!
PS> we need to know where 'has_rejected_advisories' is in the JSON so send us your json url as it must be a column/obj header name. Or it's any old 'a' then var a can be your "false"
In constructor:
this.state = {a:null};
In some function:
superagent.get(URL).then(
(res) => {for(let i in res.body)
{
if(i === 'has_rejected_advisories')
{
this.setState({a:res.body[i]})
}
}
}).catch((err)=>(err.message));
In render:
console.log(this.state.a);
Inside then() the value could be used using state variable but there are many scenarios we could not use them, like if we want to perform all the operations under constructor i.e Initializing state variable, calling superagent and changing the state variable and using the state variable.

Displaying data from Firebase in React without arrays

I am new to both React and Firebase. I struggled a bit to get data from the database, even though the instructions on the Firebase website were pretty straightforward.
I managed to print data in the view by using this code:
Get data from DB and save it in state:
INSTRUMENTS_DB.once('value').then(function(snapshot) {
this.state.instruments.push(snapshot.val());
this.setState({
instruments: this.state.instruments
});
From Firebase, I receive and Object containing several objects, which correspond to the differen instruments, like shown in the following snippet:
Object {
Object {
name: "Electric guitar",
image: "img/guitar.svg"
}
Object {
name: "Bass guitar",
image: "img/bass.svg"
}
// and so on..
}
Currently, I print data by populating an array like this:
var rows = [];
for (var obj in this.state.instruments[0]) {
rows.push(<Instrument name={this.state.instruments[0][obj].name}
image={this.state.instruments[0][obj].image}/>);
}
I feel like there's a better way to do it, can somedody give a hint? Thanks
I user firebase a lot and mu solution is little ES6 helper function
const toArray = function (firebaseObj) {
return Object.keys(firebaseObj).map((key)=> {
return Object.assign(firebaseObj[key], {key});
})
};
I also assign the firebase key to object key property, so later I can work with the keys.
The native map function only works for arrays, so using directly it on this object won't work.
What you can do instead is:
Call the map function on the keys of your object using Object.keys():
getInstrumentRows() {
const instruments = this.state.instruments;
Object.keys(instruments).map((key, index) => {
let instrument = instruments[key];
// You can now use instrument.name and instrument.image
return <Instrument name={instrument.name} image={instrument.image}/>
});
}
Alternatively, you can also import the lodash library and use its map method which would allow you to refactor the above code into:
getInstrumentRowsUsingLodash() {
const instruments = this.state.instruments;
_.map(instruments, (key, index) => {
let instrument = instruments[key];
// You can now use instrument.name and instrument.image
return <Instrument name={instrument.name} image={instrument.image}/>
});
}
Side note:
When you retrieve you data from Firebase you attempt to update the state directly with a call on this.state.instruments. The state in React should be treated as Immutable and should not be mutated with direct calls to it like push.
I would use map function:
_getInstrumentRows() {
const instruments = this.state.instruments[0];
if (instruments) {
return instruments.map((instrument) =>
<Instrument name={instrument.name}
image={instrument.image}/>);
}
}
In your render() method you just use {_getInstrumentRows()} wherever you need it.

Push objects to Array in nested loop

I'm having difficulties sending a populated array after two nested loops has completed iterating. I'm using the Async npm library and trying to use the async.forEach completion callback to send the entire array. The inner array iterates over 5 objects, which constitutes a "course" - afterwhich the course object is saved to a person object and there's multiple course objects per person object.
var self = this,
person = [],
course = [];
async.forEach(elements.value, function (element, callback1) {
self.elementIdElements(element.ELEMENT, 'td').then(function (rows) {
async.forEach(rows.value, function (cell, callback2) {
self.elementIdText(cell.ELEMENT).then(function (res) {
course.push(res.value);
callback2();
});
}, callback1);
person.push(course);
course = [];
});
}, function (err) {
res.send('grades: ' + JSON.stringify(person));
});
However, it calls the sendResponse in the middle of iterating through the arrays and I simply cannot phantom why this is happening, it should call it after iterating through the whole thing. The scope and asynchronous calls is confusing
Thanks in advance,
Chris
UPDATE - SOLUTION
I finally figured out the scope of the callbacks with the following code:
var self = this,
person = [],
course = [];
async.forEach(elements.value, function (element, callback1) {
self.elementIdElements(element.ELEMENT, 'td').then(function (rows) {
async.forEach(rows.value, function (cell, callback2) {
self.elementIdText(cell.ELEMENT).then(function (res) {
course.push(res.value);
callback2();
});
}, function (err) {
person.push(course);
course = [];
callback1();
});
});
}, function (err) {
res.send('grades: ' + JSON.stringify(person));
});
You must nest your callbacks inside each other. With the async library, the last argument of many of the calls is the "final callback", which lets you know when everything is done.
You're outer async.forEach looks good, where the final callback of sendResponse is the final argument.
Change the inner async.forEach so callback is the final argument. async.forEach(rows.value, getCourseData, callback)
I might also suggest more descriptive callback names so you can easily keep track ("innerCallback" "outerCallbacl" or "rowsCallbacl" ... whatever you want)

Getting elements from array based on property values (AngularJS)

I have an array of players, each player is an object that has a number of properties, one is "goals".
var players = [
{
"id":"4634",
"name":"A. Turan",
"number":"0",
"age":"28",
"position":"M",
"goals":"1"
},
{
"id":"155410",
"name":"H. Çalhano?lu",
"number":"0",
"age":"21",
"position":"A",
"goals":"0"
},
{
"id":"4788",
"name":"B. Y?lmaz",
"number":"0",
"age":"30",
"position":"A",
"goals":"2",
}
]
I've written a function to cycle through the array and push every element that has more than '0' goals to an array, topScorers. Like so:
$scope.topScorerSearch = function() {
var topScorers = [];
$scope.teamDetails.squad.forEach(function(o) {
if (o.goals > 0) {
topScorers.push(o)
}
});
return topScorers;
}
With the function called as {{topScorerSearch()}}.
This returns only players who have scored. Perfect.
However, I want to run this on other properties, which will result in a lot of repetitious code. How can I make this a general purpose function that can be executed on different properties?
I tried including the 'prop' parameter, but it didn't work:
$scope.topScorerSearch = function(prop) {
var topScorers = [];
$scope.teamDetails.squad.forEach(function(o) {
if (o.prop > 0) {
topScorers.push(o)
}
});
return topScorers;
}
...and called the function like this:
{{topScorerSearch(goals)}}
Why doesn't this work? Where am I going wrong?
I believe the issue is that prop will not resolve to goals because goals is being treated as a variable with a null or undefined value, making prop null or undefined.
If you use the alternative way of accessing object properties object["property"] and use the function {{topScorers("goals")}} it should work out.

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;
});

Resources