Angularjs using ng-if for selective ng-repeat - javascript

I have the following arrays:
$scope.selected_items = [
{id: "12345"},
{id: "67890"}
]
$scope.list_items = [
{ id: "12345", name: "first", more: "data" },
{ id: "22222", name: "second", more: "data2" },
{ id: "33333", name: "third", more: "data3" },
]
I am trying to list out all the items in $scope.list_items who's id is not present in $scope.selected_items. I know I have to do something with ng-if but I can't figure out what to do.
<div ng-repeat="data in list_items" ng-if="????">
{{ data.name }}
</div>
Could anyone help me figure out this problem?

I suggest storing information if the object is selected within the array itself.
e.g.:
javascript
$scope.list_items = [
{ id: "12345", name: "first", more: "data", selected: true },
{ id: "22222", name: "second", more: "data2" },
{ id: "33333", name: "third", more: "data3" selected: true },
]
html
<div ng-repeat="data in list_items | filter:{selected:false}">
{{ data.name }}
</div>

Since you mentioned you cant keep the selected state in the list_items array itself. you can probably call a function in the ng-if and check whether the item exists in the selected using a function.
<div ng-repeat="data in list_items" ng-if="checkItem(data)">
{{ data.name }}
</div>
The function will look like this,
$scope.checkItem = function(item)
{
for(var i=0;i<$scope.selected_items.length;i++)
{
var sItem = $scope.selected_items[i];
if(sItem.id===item.id)
return false;
}
return true;
}
plnkr link http://plnkr.co/edit/3a4zoKIKFABAmif0fKFt?p=preview

If it must be separated as in your example, you best bet is to create a new array with the items you want to ng-repeat.
So what you would do is something similar:
$scope.newList = [];
for (var i=0; $scope.list_items.length < i; i++) {
for (var s=0; $scope.selected_items.length < s; s++) {
if ($scope.selected_items[s].id == $scope.list_items[i].id) {
$scope.newList.push($scope.list_items[i]);
}
}
It would be ideal to do what the guy above me said, keep all of this in one object and just have a display: true/false flag in there.

Well, the correct pattern would be to use a AngularJS filter.
You just add the filter to your ngRepeat:
myApp.filter('selectedItems', function () {
return function (values, selectedItemsArr) {
console.log(values, selectedItemsArr)
var arrayToReturn = [];
// Loops through the values in the list
for (var i = 0; i < values.length; i++) {
// Now loops through the selected items array to see if it matches
for (var l = 0; l < selectedItemsArr.length; l++) {
if (values[i].id === selectedItemsArr[l].id) {
arrayToReturn.push(values[i]);
}
}
}
return arrayToReturn;
};
});
Example here: http://jsfiddle.net/Nitrium/3vcs445c/1/

Related

how to get the value by the help of includes/index of

how to get the value in any way if key does match with "Item"
const data = [{
"Item-55566": "phone",
},
{
"Items-44555": "Case",
}
];
/* How to get value if index found by Item */
for(let i = 0; i<data.length; i++) {
console.log(data[i].includes("Item"));
//Expecting phone and case
}
for-in allows you to loop through the keys in an object. Not to be confused with for-of, which loop through elements in an array.
const data = [{
"Item-55566": "phone",
},
{
"Items-44555": "Case",
}
];
for(let datum of data)
{
for(let key in datum)
{
if(key.includes("Item"))
{
console.log(datum[key]);
}
}
}
In the simple way just change data[i].includes("Item") to data[i].keys().includes("Item").
BUT! Could we have some alternative data set here? For example:
const data = [{
"Item-55566": "phone",
"SomeKey: "Some Value",
123123: "Numeric key with value"
},
{
"Items-44555": "Case",
"Another-key": "Another value"
}
];
In this case you need to put some changes in your code to find correct keys & values:
for(let i = 0; i<data.length; i++) {
data[i].keys().forEach(v=>{
String(v).includes("Item") && console.log("Got index: ${i}, key: ${v}, value: ${data[i][v]}")
})
}
The for loop iterates through the two objects, so you can check to see whether the object has that particular property using hasOwnProperty()
const data = [
{
"Item-55566": "phone",
},
{
"Items-44555": "Case",
},
];
/* How to get value if index found by Item */
for (let i = 0; i < data.length; i++) {
if (data[i].hasOwnProperty("Item-55566")) {
console.log(data[i]);
}
}
If you want to keep your loop (good that it's only one loop compared to other answers) you can do it with Object.keys and values:
const data = [{
"Item-55566": "phone",
},
{
"Items-44555": "Case",
}
];
/* How to get value if index found by Item */
for(let i = 0; i<data.length; i++) {
if(Object.keys(data[i])[0].includes('Item')){
console.log(Object.values(data[i])[0]);
}
}
You can use .filter to filter all items of the data array which includes Item text.
Then you can use .map to render new value from each object comes from data array.
const data = [
{"Item-55566": "phone", },
{ "Items-44555": "Case",},
{ "Other-44555": "Nope",}];
var filteredItems = data.filter(item => Object.keys(item)[0].includes("Item"));
console.log(filteredItems.map(item => Object.values(item)[0]));
Refactor code - By using .reduce()
const data = [
{"Item-55566": "phone", },
{ "Items-44555": "Case",},
{ "Other-44555": "Nope",}];
var res = data.reduce((prev, curr) =>
{
var entries = Object.entries(curr)[0];
if(entries[0].includes("Item"))
prev.push(entries[1]);
return prev;
}, []);
console.log(res);

Building an recursive tree from another

I have an problem with building an recursive tree from another. The function seems to work but if you expand the first array you'll notice that there is an endless recursion at index 2.
My function which builds the tree:
var buildTree = function(data, idx, aparent){
var parent = aparent || [];
for(var i = 0, c = data.length ; i < c ; i++){
parent.push({
text: data[i].text,
items: []
});
if(typeof data[i].items !== 'undefined' && data[i].items.length > 0){
var t = buildTree(data[i].items, idx + 1, parent[parent.length - 1].items);
parent[parent.length - 1].items.push(t);
}
}
return parent;
};
And that's how my tree data looks like:
[{
text: "house",
groupId: "1",
type: "group",
items: [{
text: "basement",
groupId: "2",
type: "group"
},{
text: "flat-1",
groupId: "3",
type: "group",
items: [{
text: "computer"
}]
}]
},{
text: "other-house",
groupId: "4",
type: "group"
}];
I think i has something to do that javascript returns the value by reference...
Here's a plunk with the complete data, check the console to after clicking the button to get an idea what i mean.
I can't really get my head around your code. Maybe your problem has something to do with the fact that you pass in the items-array during your recursion.
I have fixed up your code - making it a bit more simple and easy to read. It relies on the property items being an array if present, so if that is not always the case you need to add error handling for this scenario.
function recursiveBuildTree(data) {
var result = [];
data.forEach(function(item) {
var newItem = {
text: item.text,
items: item.items ? recursiveBuildTree(item.items) : []
};
result.push(newItem);
});
return result;
}

How to add property to nested javascript array (of objects)?

I am trying to add a property to javascript nested array object...
I need to traverse the tree get the value of text property and convert it to lowercase and add this data as new property (lowerText)
Old array:
var oldObject= [{
text: "Subgroup3",
items: [{
text: "subgroup5",
items: [{
text: "subgroup6",
items: [{
text: "subgroup7",
items: [{
text: "subgroup8"
}]
}]
}]
}]
}]
I need the new array object as below:
var newObject= [{
text: "Subgroup3",
lowerText:"subgroup3",
items: [{
text: "subgroup5",
lowerText:"subgroup5",
items: [{
text: "subgroup6",
lowerText:"subgroup6",
items: [{
text: "subgroup7",
lowerText:"subgroup7",
items: [{
text: "subgroup8",
lowerText:"subgroup8",
}]
}]
}]
}]
}]
This is what I tried, looping through each object and passing the items (array) to recursive function to set the property but it doesn't seem to work fine. Not sure what I am doing wrong, can someone please help me with this code?
for (var i = 0; i < data.length; i++) {
data[i].lowerText=data[i].text.toLowerCase();
loopTree(data[i].items);
}
function loopTree(node){
if (node) {
$.each(node, function (idx, item) {
item.lowerText=item.text.toLowerCase();
if(item.items){
loopTree(item.items)
}
});
}
}
EDIT: Below code did the job.
for (var i = 0; i < data.length; i++) {
if(data[i]){
process( data[i]);
}
}
function process(val) {
val.lowerText = val.text.toLowerCase();
if(val.items){
for(var i = 0, len = val.items.length; i < len; i++) {
process(val.items[i]);
}
}
}
If you don't want to clone the objects and just modify the existing ones, try this:
function process(val) {
val.lowerText = val.text.toLowerCase();
for(var i = 0, len = val.items.length; i < len; i++) {
process(val.items[i]);
}
}
process(obj);
If you want to preserve the value in the old array, just push the new object onto the old array:
oldObject.push(newObject[0]);
If you just need to replace the entire array, its trivial,
oldObject = newObject;

combine js array's

pretty simple question, can't quite fig. it out.
I have 2 js array's that I need to combine into a new array, based on sub_key.
var items = [
Object {
OBJECTID=1,
Name="COMMAND B",
ID="AR0xx",
sub_key="1000"
},
Object {
OBJECTID=2,
Name="95TH PCT",
ID="AR0xx",
sub_key="1001"
},
Object {
OBJECTID=379,
Name="dummy4",
ID="AR0xx",
sub_key="9999"
}
];
var subitems = [
Object {
OBJECTID=787,
ID="AR0xx",
sub_key=1000,
Long_Name = foo
},
Object {
OBJECTID=789,
ID="AR0xx",
sub_key=1001,
Long_Name = "bar"
},
Object {
OBJECTID=1,
ID="AR0xx",
sub_key=1001,
Long_Name="baz"
},
Object {
OBJECTID=788,
ID="AR0xx",
sub_key=1001,
Long_Name="buzzz"
}
];
I'd like to create an array like so, which just combines the above 2, based on sub_key
var data = [
COMMAND B=["foo"],
95TH PCT=["bar","baz","buzz"]
dummy4=[]
];
Here's what I tried but it doesn't work... i think i'm close?? thanks for any help!
data = [];
for (var key in items){
var o = items[key];
//data.push(o.Name);
for (var subkey in subitems){
subo = subitems[subkey];
if (o.sub_key == subo.sub_key){
data[o.Name].push(subo.Long_Name)
}
}
}
Cleaning up your script, here is what you are trying to do. It craetes an array of objects using the Name from items and matching sub_key from sub_items.
var items = [
{ OBJECTID: 1,
Name: 'COMMAND B',
ID: 'AR0xx',
sub_key: '1000'
},
{ OBJECTID: 2,
Name: '95TH PCT',
ID: 'AR0xx',
sub_key: '1001'
},
{ OBJECTID: 379,
Name: 'dummy4',
ID: 'AR0xx',
sub_key: '9999'
}
];
var subitems = [
{ BJECTID: 787,
ID: 'AR0xx',
sub_key: '1000',
Long_Name: 'foo'
},
{ OBJECTID: '789',
ID: 'AR0xx',
sub_key: '1001',
Long_Name: 'bar'
},
{ OBJECTID: '1',
ID: 'AR0xx',
sub_key: 1001,
Long_Name: 'baz'
},
{ OBJECTID: '788',
ID: 'AR0xx',
sub_key: '1001',
Long_Name: 'buzzz'
}
];
var j = subitems.length;
var result = {};
var p;
var sub_key;
var obj;
for (var i=0, iLen = items.length; i<iLen; i++) {
p = items[i].Name;
result[p] = [];
sub_key = items[i].sub_key;
for (var j=0, jLen=subitems.length; j<jLen; j++) {
if (subitems[j].sub_key == sub_key) {
result[p].push(subitems[j].Long_Name);
}
}
}
alert(result['95TH PCT']); // bar, baz, buzz
Edit
Return a single object rather than an array of objects, which I think is what is required.
var newarray = items.slice(0); // make a copy
addloop: for (var i=0; i<subitems.length; i++) {
for (var j=0; j<newarray.length; j++)
if (subitems[i].sub_key == newarray[j].sub_key)
continue addloop;
newarray.push(subitems[i]);
}
should work. Another solution:
Array.prototype.combine = function(a, test) {
if (typeof test == "function") {
for (var i=0; i<a.length; i++)
if (! this.some(test.bind(null, a[i])))
this.push(a[i]);
} else {
for (var i=0; i<a.length; i++)
if (this.indexOf(a[i]) == -1)
this.push(a[i]);
}
return this;
};
var newarray = items.slice(0).combine(subitems, function(a, b) {
return a.sub_key == b.sub_key;
});
I wrote this on the train but didn't get to post it, and it looks like a couple of other people posted good answers since, but it might still be helpful so I'll post it anyways
I had a few different things to note:
var items = [
Object {
OBJECTID=1,
Name="COMMAND B",
ID="AR0xx",
sub_key="1000"
},
...
You don't need the word Object here, you can just write { ... } and JS knows it's an object.
Within an object, you need : instead of =
It's not required, but putting the key in quotes is good practice because some keys won't work otherwise.
So it should look like this:
var items = [
{
"OBJECTID": 1,
"Name": "COMMAND B",
"ID": "AR0xx",
"sub_key": "1000"
},
...
Next up, I'm not completely clear on what you're doing with your data array in the second block, but it looks like you're overriding it with an empty array in the third block.
Also, I think you may be confusing Objects and Arrays somewhat. http://nfriedly.com/techblog/2009/06/advanced-javascript-objects-arrays-and-array-like-objects/ has a good overview of the differences, but here's some key points:
Array is a subclass of Object
Array values always have numeric indexes, not string keys
push() is a method of Array not Object
Next up, your loop. for .. in style loops do work on arrays, but they're not generally recommended because they can also hit keys that were added to the underlying Object. forEach is my favorite but it's not always available in older browsers without a library such as underscore.js.
for(var i=0, len=MyArray.length; i<len; i++) {...} is the other option that you'll see very commonly because it covers all of the array items but does not have the possibility of hitting the underlying object.
But, since Bergi and RobG both have good loops, I'll stop here.

Jquery object search

I have the following object and what I would like achieve is to get the index of theme if the name has match with a variable.
for example: I'm making a loop in the views and if my task (something1) variable has matches with the name element than to return the index of object.
By the given example I should have as result 0,
var views = [
{
name: "something1",
type: something1,
columns: something1
},
{
name: "something2",
type: something2,
columns: something2
},
{
name: "something3",
type: something3,
columns: something3
}
];
var task = 'something1';
$.each(views, function(index, value) {
if (value.name = task) {
alert(index);
}
});
You dont really need jQuery for this:
See: http://jsfiddle.net/enNya/2/
var views = [
{
name: "something1",
type: "something1",
columns: "something1"
},
{
name: "something2",
type: "something2",
columns: "something2"
}
];
var task = 'something2';
// Set a var and maintain scope
var i;
// Loop each element of the array
for (i = 0; i < views.length; i++) {
// If the X = Y the stop looping
if (views[i].name == task) {
break;
}
}
// Check if it was not found
i = i == views.length ? false : i;
// Log the result
console.log(i);
It's just a matter of syntax, as lgt said don't forget toseparate elements within your object with commas. Aslo the correct 'equal' operator is '=='.
'value.name=task' would be always true. It means can I affect the content of 'task' into 'value.name'.
Here is your valid js.
Note that in this example you'll get 2 alertbox.. ;)
var views=[
{
name:"something1",
type:'something1',
columns:'something1'
},
{
name:"something1",
type:'something1',
columns:'something1'
},
{
name:"something2",
type:'something2',
columns:'something2',
},
];
var task='something1';
$.each(views, function(index, value) {
if (value.name==task){
alert(index);
}
});
replace something1 variable for 0 and value.name == task (double =)
var views=[{
name:"something1",
type:0,
columns:0
}, {
name:"something1",
type:0,
columns:0
}, {
name:"something2",
type:0,
columns:0
}];
var task='something1';
$.each(views, function(index, value) {
if (value.name==task){
return index;
}
});

Categories