Angularjs Splice in Nested Array - angularjs

Hi can somebody help Removing element from nested json array like this
JSON
[{
"id": 1,
"name": "Furniture & Fixture",
"choice": {
"0": {
"req_goods": "table",
"qty": "10"
},
"1": {
"req_goods": "chair",
"qty": "5"
}
}
}, {
"id": 2,
"name": "Miscellaneous Property",
"choice": {
"0": {
"req_goods": "Office Rent",
"qty": "1"
}
}
}]
here how do I remove choice 1 of id 1 .
HTML
<div ng-repeat="cb in capital_budgets">
<div ng-repeat="choice in choices[$index]">
<input ng-model="cb.choice[$index].req_goods">
<input ng-model="cb.choice[$index].qty">
<button ng-hide="$first" ng-click="removeChoice($parent.$index,$index)">-</button>
</div>
<button ng-click="addNewChoice($index)">+</button>
</div>
JS
$scope.capital_budgets = [{"id":1,"name":"Furniture & Fixture"},
{"id":2,"name":"Miscellaneous Property"}];
$scope.choices = [{}];
$scope.choices[0] = [{}];
$scope.choices[1] = [{}];
$scope.choices[2] = [{}];
$scope.choices[3] = [{}];
$scope.choices[4] = [{}];
$scope.addNewChoice = function(id) {
$scope.choices[id].push({});
};
$scope.removeChoice = function(parent_id, id) {
$scope.choices[parent_id].splice(id, 1);
};
The Above removeChoice() remove last element but I want to remove the element that user choose to remove. please help i have been trying from 2 days.

You can make 'choice' of the array type as follows and use the index of the particular choice in the ng-repeat directive to remove the choice from the choices array.
angular
.module('demo', [])
.controller('DefaultController', DefaultController);
function DefaultController() {
var vm = this;
vm.items = [
{
"id": 1,
"name": "Furniture & Fixture",
"choices": [
{
"id": 1,
"req_goods": "table",
"qty": "10"
},
{
"id": 2,
"req_goods": "chair",
"qty": "5"
}]
}, {
"id": 2,
"name": "Miscellaneous Property",
"choices": [
{
"id": 1,
"req_goods": "Office Rent",
"qty": "1"
}]
}];
vm.removeChoice = removeChoice;
vm.addChoice = addChoice;
function removeChoice(itemId, index) {
for (var i = 0; i < vm.items.length; i++) {
if (vm.items[i].id === itemId) {
vm.items[i].choices.splice(index, 1);
break;
}
}
}
function addChoice(index) {
var id = vm.items[index].choices.length + 1;
vm.items[index].choices.push({
id: id,
req_goods: "",
qty: 0
});
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demo">
<div ng-controller="DefaultController as ctrl">
<div ng-repeat="item in ctrl.items">
<h3>{{item.name}}</h3>
<div ng-repeat="choice in item.choices">
<input type="text" ng-model="choice.req_goods" />
<input type="text" ng-model="choice.qty" />
<button type="button" ng-click="ctrl.removeChoice(item.id, $index)">Remove</button>
</div>
<button type="button" ng-click="ctrl.addChoice($index)">Add</button>
</div>
</div>
</div>

You can remove choice "1" of id 1 using the below code snippet.
var json = [
{
"id": 1,
"name": "Furniture & Fixture",
"choice": {
"0": {
"req_goods": "table",
"qty": "10"
},
"1": {
"req_goods": "chair",
"qty": "5"
}
}
}, {
"id": 2,
"name": "Miscellaneous Property",
"choice": {
"0": {
"req_goods": "Office Rent",
"qty": "1"
}
}
}];
function removeChoice(json, parentId, choice) {
for (var i = 0; i < json.length; i++) {
if (json[i].id === parentId) {
delete json[i].choice[choice];
break;
}
}
}
removeChoice(json, 1, "1");
console.log(json);
If you want the the choice also to be of the same type as its parent element i.e. an array you could change your JSON as follows and do as shown in the below code snippet to remove a choice from the JSON
var json = [
{
"id": 1,
"name": "Furniture & Fixture",
"choices": [
{
"id": 1,
"req_goods": "table",
"qty": "10"
},
{
"id": 2,
"req_goods": "chair",
"qty": "5"
}]
}, {
"id": 2,
"name": "Miscellaneous Property",
"choices": [
{
"id": 1,
"req_goods": "Office Rent",
"qty": "1"
}]
}];
function removeChoice(json, parentId, choiceId) {
for (var i = 0; i < json.length; i++) {
if (json[i].id === parentId) {
for (var j = 0; j < json[i].choices.length; j++) {
if (json[i].choices[j].id === choiceId) {
json[i].choices.splice(j, 1);
break;
}
}
break;
}
}
}
removeChoice(json, 1, 1);
console.log(json);
In both of the above methods I've passed the source you want to modify as a parameter to the removeChoice function whereas you can also directly use a variable available within the scope of execution of the removeChoice function and pass only parentId and choiceId as parameters in the below code snippet, you can replace items with the object on your controller's $scope.If you prefer isolation of the code you can pass the items object as a parameter to the removeChoice function as it won't be dependent on the external components directly being used in the method body, I would suggest to have separation of concerns.
var items = [
{
"id": 1,
"name": "Furniture & Fixture",
"choices": [
{
"id": 1,
"req_goods": "table",
"qty": "10"
},
{
"id": 2,
"req_goods": "chair",
"qty": "5"
}]
}, {
"id": 2,
"name": "Miscellaneous Property",
"choices": [
{
"id": 1,
"req_goods": "Office Rent",
"qty": "1"
}]
}];
function removeChoice(parentId, choiceId) {
for (var i = 0; i < items.length; i++) {
if (items[i].id === parentId) {
for (var j = 0; j < items[i].choices.length; j++) {
if (items[i].choices[j].id === choiceId) {
items[i].choices.splice(j, 1);
break;
}
}
break;
}
}
}
removeChoice(1, 1);
console.log(items);

Try This
$scope.removeChoice = function(parent_id,id) {
var TempArr=[];
var parentLength=$scope.choices[parent_id].length;
for(i=0;i<parentLength;i++ ){
if(parentLength[i]!==id){
TempArr.push(parentLength[i]);
}
if(i==parentLength-1){
$scope.choices[parent_id]=[];
$scope.choices[parent_id]=TempArr;
}
}
};

Related

I can't use filter when I have objects inside an array and find last id, angular

I need your opinion in this situation:
I get from API with this function:
getRS(
idProject: string
): Observable<ResponseModel<RSModel>> {
return this.http.get<ResponseModel<RSModel>>(
ApiUrlsConfig.getRS(
idProject
)
);
}
this response:
{
"data": [
{
"id": "id1",
"state": 1,
"note": null
},
{
"id": "id1",
"state": 2,
"note": "Reason 1"
},
{
"id": "id2",
"state": 2,
"note": "Reason updated3",
}
],
"result": null
}
I need to use filter in this response because I should be get the last state for each id. For example, I want to display state 2 in item with id: id1. For this I want to use filter. The problem is because I can't use filter on it, I don't understand why.
I tried to write this code:
#Input() set jobId(jobId: string) {
this.optionsService
.getRS(
this.idProject
)
.pipe()
.subscribe((res) => {
let resId = res.filter((aaa)=>{
if(aaa.id === jobId){
res.slice(-1)[0].id
}
}
)
});
}
Not function.
Please can you share with me any idea?
Thank you
Try this logic:
Loop backwards throw it.
Loop backwards over index to the start.
Splice duplicates.
let response = {
"data": [
{
"id": "id1",
"state": 1,
"note": null
},
{
"id": "id1",
"state": 2,
"note": "Reason 1"
},
{
"id": "id2",
"state": 2,
"note": "Reason updated3"
}
],
"result": null
}
let data = response.data;
for (let i = data.length - 1; i >= 0; i--) {
for (let j = i - 1; j >= 0; j--) {
if (data[i].id === data[j].id) {
data.splice(j, 1);
j++;
}
}
};
console.log(data);
try this:
if(aaa.id == jobId){
return res.slice(-1)[0].id
}

Issue with the object references in Angularjs

I have a simple function below using which am trying create dynamic div containing a d3 chart for each row from the given input "json.res_full_sk"
However, when I use apply in Angularjs, am losing the historic data that is being assigned to dyndata object.
<script>
var app = angular.module('rpPlotExampleApp', ['ui.rpplot']);
app.controller('rpPlotCtrl', function ($scope) {
$scope.dyndata={};
$scope.assign_sk = function (testjsobj) {
alert('From Angular JS'+ JSON.stringify(testjsobj));
$scope.dyndata=testjsobj;
};
});
</script>
<script type="text/javascript">
jsonList = [];
jsonList.res_full_sk = [
{ "tid": 20, "sk": [{ "name": "Banking", "value": 40, "id": 0 }, { "name": "Housing", "value": 4, "id": 1 }, { "name": "Home", "value": 4, "id": 2 }, { "name": "NET", "value": 4, "id": 3 }] },
{ "tid": 22, "sk": [{ "name": "Movie", "value": 12, "id": 0 }, { "name": "Movie2", "value": 4, "id": 1 }, { "name": "Housing", "value": 4, "id": 2 }, { "name": "Banking", "value": 4, "id": 3 }, { "name": "C", "value": 4, "id": 4 }] },
{ "tid": 24, "sk": [{ "name": "Housing", "value": 4, "id": 0 }, { "name": "Home", "value": 4, "id": 1 }, { "name": "Banking", "value": 4, "id": 2 }] }
];
arr = [];
function getObjContents(i) {
arr = $.grep(jsonList.res_full_sk, function (e) {
return e.tid == i;
});
var str = "";
for (var i = 0; i < arr[0].sk.length; i++) {
str += ","+ JSON.stringify(arr[0].sk[i]);
}
str=str.substring(1);
str = "[" + str + "]";
str_obj=JSON.parse(str);
str_fin = {};
str_obj.forEach(function (e, i) {
str_fin['d' + i] = e;
});
return str_fin;
}
function insertDiv(Num) {
array = [];
var ar1 = Num.replace('[', '');
array = JSON.parse("[" + ar1 + "]");
var i = 0;
for (i; i < array.length; i++) {
js_data={};
js_data=getObjContents(array[i]);
testjsobj=js_data;
var scope = angular.element(document.getElementById("rpPlotCtrl")).scope();
scope.$watch("dyndata", function (oldval, newval) {
}, true);
scope.$apply(function () {
scope.dyndata = js_data;
});
var id_num;
id_num = array[i];
var rChart = angular.element(document.getElementById("sktemp"));
rChart.injector().invoke(function ($compile) {
$('<div obj></div>').insertAfter("#sktemp")
var obj = $('[obj]'); // get wrapper
var scope1 = $('[obj]').scope();
// generate dynamic content
alert(JSON.stringify(scope1.dyndata));
obj.html("<div class='skpro' id='skpro" + id_num + "' name='cn'><div class='skprovis' id='skprovis" + id_num + "' >Hello " + id_num + "<div class='half-plot' style='height:95%;width:95%;margin-top:0px;margin-left:5px;'><rp-plot dsn='dyndata' point-radius='1.5' scale='log' labelled='true' class='plot-rp-plot'></rp-plot></div></div></div>");
// compile!!!
console.log(obj.contents());
$compile(obj.contents())(scope1);
scope1.$apply();
});
}
}
</script>
The problem is dyndata is being changed for each value of i in the for loop, and thus the d3 chart is updated with the lastly assigned dyndata object.
As I see the dyndata object is being assigned with different values each time for loop executes, but it is not remaining but changes with the next value of dyndata to all the charts that were created.
How can I get the historic data to persist for dyndata that is already rendered for each for loop execution?
Am new to Angularjs and not very sure how I can make use of Angular.copy() for this scenario.
Problem seems to be with below code -
var scope = angular.element(document.getElementById("rpPlotCtrl")).scope();
scope.$watch("dyndata", function (oldval, newval) {
}, true);
scope.$apply(function () {
scope.dyndata = js_data;
});
as soon as I assign new js_data value to dyndata, all the existing charts gets updated with new value.
I tried using angular.copy(scope.dyndata)=js_data.. But it didn't work out.
Can you please suggest me?

Angular filtering object based on array of strings

I'd like to be able to filter an entire object based on an array of strings. Currently the default filter will search an entire object based on a single string value, but not with an array of strings.
current jsfiddle
<div ng-controller="myController">
<div>
<ul determine-filtering>
<li get-filter-tag active-state="false" tag="{{button}}"
ng-repeat="button in buttons">
{{button}}
</li>
</ul>
<hr/>
<ul>
<li ng-repeat="item in content | filter:filterArray">
{{item.data.headline}}
</li>
</ul>
</div>
</div>
app.js
var testapp = angular.module('testapp', [])
.filter('inArray', function($filter){
return function(list, arrayFilter){
if(arrayFilter.length > 0){
console.log(arrayFilter);
return $filter("filter")(list, function(listItem){
return arrayFilter.indexOf(listItem) != -1;
});
}else{
return $filter("filter")(list, function(listItem){
return arrayFilter.indexOf(listItem) == -1;
});
}
};
})
.directive('getFilterTag', function () {
return {
link: function postLink(scope, element, attrs) {
element.on('click', function(){
var tag = attrs.tag;
var filterArray = scope.filterArray;
if(filterArray.indexOf(tag) === -1){
scope.filterArray.push(tag);
}else{
filterArray.splice(filterArray.indexOf(tag), 1);
}
scope.$apply();
});
}
};
})
.directive('activeState', function () {
return {
link: function (scope, element, attrs) {
element.on('click', function(){
attrs.activeState = !attrs.activeState;
if(!attrs.activeState){
$(this).addClass('active');
}else{
$(this).removeClass('active');
};
});
}
};
})
.controller('myController', function($scope){
$scope.filterArray = [];
$scope.buttons = ['corn', 'vegetable', 'onion'];
$scope.content = [
{
"type": [
"recipe"
],
"data": {
"prepTimeInMinutes": 10,
"serves": "6 to 8",
"headline": "North Carolina Piedmont Slaw",
"ingredients": [
{
"item": "medium head cabbage",
"quantity": {
"number": 1
},
"notes": "cored and chopped (5 to 6 cups)"
},
{
"unit": "cup",
"item": "ketchup",
"quantity": {
"number": 1
}
},
{
"unit": "tbsp.",
"item": "sugar",
"quantity": {
"number": 3
}
},
{
"unit": "tbsp.",
"item": "apple cider vinegar",
"quantity": {
"number": 1
}
},
{
"unit": "tsp.",
"item": "kosher salt",
"quantity": {
"fraction": {
"display": "½",
"denominator": 2,
"numerator": 1
}
}
},
{
"unit": "tsp.",
"item": "black pepper",
"quantity": {
"fraction": {
"display": "½",
"denominator": 2,
"numerator": 1
}
},
"notes": "freshly ground"
},
{
"item": "Generous dash hot sauce, such as Texas Pete Hot Sauce or Tabasco brand"
}
],
"description": "",
"cookTimeInMinutes": 180,
"categories": {
"Dish Type": [
"Side"
],
"Main Ingredient": [
"Vegetable"
]
},
"cookingDirections": [
{
"step": "Place the cabbage in a large bowl."
},
{
"step": "Combine the ketchup, sugar, vinegar, salt, pepper and hot sauce in a liquid measuring cup. Pour over the cabbage and toss to coat thoroughly. Cover and refrigerate for at least 3 hours, and preferably overnight, before serving."
},
{
"step": "Serve on top of the pulled pork"
}
]
}
}
]
} );
I have a custom filter which worked with arrays, but not with arrays with nested objects. What is the best approach to do this kind of filtering? Is there anything the $filter service already provides for searching based on arrays?
If you need to filter an object based on an array of strings (matching the objects properties) I would look into lodash#omit.
Usage:
var obj = { a: 'a', b: 'b', c: 'c' };
var arr = ['a', 'c'];
_.omit(obj, arr); // { b: 'b' }
I'm not sure whether omit supports deep/nested objects. If not, you could compose it with an iterator to determine whether the given key of an object is an object itself and run another omit on that.

AngularJS - Filter out single object in nested data structure

Data
var data = {
"records": [
{
"name": "Spectrum Series",
"seriesid": "SpectrumSeries",
"book": [
{
"name": "White Curse",
"bookid": "WhiteCurse",
"image": "book1"
},
{
"name": "Blue Fox",
"bookid": "BlueFox",
"image": "book2"
}
]
… other series
}
Controller
dnleoApp.controller('BookCtrl', function ($scope, $routeParams) {
$scope.mybookid = $routeParams.bookid;
$scope.myseriesid = $routeParams.seriesid;
$scope.serieslist = data.records;
$scope.compareSeriesID = function($series) {
return $series.seriesid == $scope.myseriesid;
};
$scope.compareBookID = function($book) {
return $book.bookid == $scope.mybookid;
};
});
html
<div ng-repeat="series in serieslist | filter: compareSeriesID">
<ul ng-repeat="book in series.book | filter: compareBookID">
<li>{{book.name}}</li>
</ul>
</div>
I use nested ng-repeat with filter to filter out a single book of a series using the seriesid (unique) and bookid (unique) from the url. This approach works well but is there a cleaner way to do this?
I used nested forEach in the controller to filter out and assign the book object to a scope variable.
HTML
<div>{{selectedbook.name}}</div>
Controller
dnleoApp.controller('BookCtrl', function ($scope, $routeParams) {
$scope.mybookid = $routeParams.bookid;
$scope.myseriesid = $routeParams.seriesid;
$scope.serieslist = data.records;
var keepGoing=true;
angular.forEach($scope.serieslist, function(series){
if(keepGoing) {
if(series.seriesid == $scope.myseriesid){
angular.forEach(series.book, function(book){
if(book.bookid == $scope.mybookid){
$scope.selectedbook = book;
keepGoing = false;
}
});
}
}
});
});
if you change your data to
var data = {
"records": {
"SpectrumSeries": {
"name": "Spectrum Series",
"seriesid": "SpectrumSeries",
"book": {
"book1": {
"name": "White Curse",
"bookid": "WhiteCurse",
"image": "book1"
},
"book2": {
"name": "Blue Fox",
"bookid": "BlueFox",
"image": "book2"
}
}
},
"Series2": {
"name": "Spectrum Series",
"seriesid": "SpectrumSeries",
"book": {
"book1": {
"name": "White Curse",
"bookid": "WhiteCurse",
"image": "book1"
},
"book2": {
"name": "Blue Fox",
"bookid": "BlueFox",
"image": "book2"
}
}
}
}
}
Then you can just do serieslist[myseriesid].book[bookid] to get the book.
check this fiddle jsfiddle.net/devjit/wdtk370z/5
Or you can set the selected book in controller like
$scope.selectedBook = data.record[$routeParams.seriesid].book[$routeParams.bookid];
and in HTML
{{selectedBook.name}}

Create a treeview array of object in Angular

I want to create a treeview array for use in Angular UI Tree. I want to create the structure from a array of object like this:
0: Object
body: null
categoryDescription: null
categoryTopic: null
description: null
faqBodyId: 0
faqCategoryId: 0
faqGroupId: 1
groupDescription: null
groupName: "Generelt"
groupTopic: "Generelt"
themeCode: "GEN"
topic: null
1: Object body: null categoryDescription: "Test af kategori" categoryTopic: "Mail" description: null faqBodyId: 0 faqCategoryId: 2 faqGroupId: 1 groupDescription: null groupName: null groupTopic: null themeCode: null topic: null
2: Object body: "This is a test" categoryDescription: null categoryTopic: null description: "Testing" faqBodyId: 3 faqCategoryId: 2 faqGroupId: 0 groupDescription: null groupName: null groupTopic: null themeCode: null topic: "Test123"
etc...
It is in three levels. Group, Category and Body
A node does not allways have a child!
I want It in this structure and three levels:
[
{
"id": 1,
"title": "1. dragon-breath",
"items": []
},
{
"id": 2,
"title": "2. moiré-vision",
"items": [
{
"id": 21,
"title": "2.1. tofu-animation",
"items": [
{
"id": 211,
"title": "2.1.1. spooky-giraffe",
"items": []
},
{
"id": 212,
"title": "2.1.2. bubble-burst",
"items": []
}
]
},
{
"id": 22,
"title": "2.2. barehand-atomsplitting",
"items": []
}
]
},
{
"id": 3,
"title": "3. unicorn-zapper",
"items": []
},
{
"id": 4,
"title": "4. romantic-transclusion",
"items": []
}
]
Structure
How is that done with Angular code?
I solved the problem like this.
The input array is sorted:
function buildtree(arr) {
var group = [];
angular.forEach(arr, function (value, index) {
if (value.faqGroupId > 0 && value.faqCategoryId == 0 && value.faqBodyId == 0) {
var category = [];
var faqgroup = {
"id": value.faqGroupId,
"title": value.groupTopic,
"description": value.groupDescription,
"name": value.groupName,
"items": category
}
angular.forEach(arr, function (valuecat, index) {
if (value.faqGroupId == valuecat.faqGroupId && valuecat.faqCategoryId > 0 && valuecat.faqBodyId == 0) {
var body = [];
var faqcat = {
"id": valuecat.faqCategoryId,
"title": valuecat.categoryTopic,
"description": valuecat.categoryDescription,
"items": body
}
angular.forEach(arr, function (valuebod, index) {
if (valuecat.faqGroupId == valuebod.faqGroupId && valuecat.faqCategoryId == valuebod.faqCategoryId && valuebod.faqBodyId > 0) {
var faqbody = {
"id": valuebod.faqBodyId,
"title": valuebod.topic,
"description": valuebod.description,
"body": valuebod.body,
}
body.push(faqbody);
}
})
category.push(faqcat);
}
})
group.push(faqgroup);
}
});
return group;
}
Array list :
Flat object array list
var dataList= [
{'id':1 ,'parentid' : 0, 'label'="label 1"},
{'id':4 ,'parentid' : 2 ,'label'="label 2"},
{'id':3 ,'parentid' : 1, 'label'="label 3"},
{'id':5 ,'parentid' : 0, 'label'="label 4"},
{'id':6 ,'parentid' : 0, 'label'="label 5"},
{'id':2 ,'parentid' : 1, 'label'="label 6"},
{'id':7 ,'parentid' : 4, 'label'="label 7"},
{'id':8 ,'parentid' : 1, 'label'="label 8"}
];
covert flat object array list to treeview list
function flatListToTreeViewData(dataList) {
var tree = [],
mappedArr = {},
arrElem,
mappedElem;
for (var i = 0, len = dataList.length; i < len; i++) {
arrElem = dataList[i];
mappedArr[arrElem.id] = arrElem;
mappedArr[arrElem.id]['children'] = [];
}
for (var id in mappedArr) {
if (mappedArr.hasOwnProperty(id)) {
mappedElem = mappedArr[id];
array of children.
if (mappedElem.parentID) {
mappedArr[mappedElem['parentID']]['children'].push(mappedElem);
}else {
tree.push(mappedElem);
}
}
}
return tree;
}

Resources