how do i access deeply nested json object in angularjs - angularjs

Here, I am suppose to access the top level market details from the Json data on the first page which I'm able to although Im not able to access the sub level market details. Im suppose to display the sub level market names on the next page.
$scope.myData = {
"market": [{
"mid": 3,
"mname": "mark1",
"submarket": [{
"id": 20,
"name": "val1"
}, {
"id": 24,
"name": "val2",
"submarket": [{
"id": 26,
"name": "val21"
}]
}]
"market": [{
"mid": 4,
"name": "mark1.1",
"submarket": [{....
}]
}]
}, {
"mid": 6,
"mname": "mark2",
}]
};
$scope.markname = []; /*stores top level markets*/
angular.forEach($scope.myData.market, function(org) {
$scope.markname.push(org)
}) /*works fine and has the details of market (mid:3 and mid:6)*/
$scope.submark = [];
angular.forEach($scope.markname.submarket, function(sorg) {
$scope.submark.push(sorg)
}) /*doesn't store anything*/

It should be:
$scope.submark = [];
angular.forEach($scope.markname, function(sorg) {
angular.forEach(sorg.submarket, function(subsorg) {
$scope.submark.push(subsorg)
});
});
JSFiddle

$scope.markname is an array and your pushing items into it on your first forEach, however in the second your trying to access the property submarket. This doesn't exist on the markname array, it exists on each item within the array.
Ive done my example using the native forEach there's no need for angular to get involved here at all, it also hides the undefined issue, as the native is available of the array prototype it throws an exception if you try to call it of undefined, whilst angular happily accepts undefined and continues.
So a simple fix would be
markname.forEach(function(sorg) {
if (sorg.hasOwnProperty('submarket')) {
submark.push(sorg.submarket);
}
});
See fiddle: https://jsfiddle.net/0y6r0mw1/
edit: Its worth noting this will produce a multidimensional array, if this is not wanted you can concat them all together with something like:
submark.push.apply(submark, sorg.submarket);

The json data that you have shared, is improper. Please go through this demo.
HTML:
<div ng-app="app" ng-controller="test">
</div>
JS:
var app = angular.module('app', []);
app.controller('test', function ($scope) {
$scope.myData = {
"market": [{
"mid": 3,
"mname": "mark1",
"submarket": [{
"id": 20,
"name": "val1"
}, {
"id": 24,
"name": "val2",
"submarket": [{
"id": 26,
"name": "val21"
}]
}, {
"mid": 4,
"name": "mark1.1",
"submarket": [{
"id": 27,
"name": "val221"
}]
}]
}, {
"mid": 6,
"mname": "mark2",
}]
};
$scope.markname = []; /*stores top level markets*/
angular.forEach($scope.myData.market, function (org) {
$scope.markname.push(org)
}) /*works fine and has the details of market (mid:3 and mid:6)*/
console.log('markname', $scope.markname);
$scope.submark = [];
angular.forEach($scope.markname, function (sorg) {
angular.forEach(sorg.submarket, function (subM) {
$scope.submark.push(subM)
})
})
console.log('submark', $scope.submark);
});

function iterate(obj) {
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
if (typeof obj[property] == "object") {
iterate(obj[property]);
}
else {
console.log(property + " " + obj[property]);
}
}
}
}
iterate(object)

Related

How to Join Multiple Arrays inside filter function of Arrays in Typescript

I am using Typescript in an Angular/Ionic project. I have an array of users that contain an array of skills. I have to filter users based on their online status as well as skills.
[
{
"id": 1,
"name": "Vikram Shah",
"online_status": "Online",
"skills": [{
"id": 2,
"title": "CSS"
},
{
"id": 3,
"title": "JavaScript"
},
{
"id": 4,
"title": "Python"
}
]
},
{
"id": 1,
"name": "Abhay Singh",
"online_status": "Online",
"skills": [{
"id": 1,
"title": "HTML"
},
{
"id": 2,
"title": "CSS"
},
{
"id": 3,
"title": "JavaScript"
},
{
"id": 4,
"title": "Python"
}
]
},
{
"id": 1,
"name": "Test Oberoi",
"online_status": "Online",
"skills": [{
"id": 1,
"title": "HTML"
},
{
"id": 2,
"title": "CSS"
},
{
"id": 3,
"title": "JavaScript"
},
{
"id": 4,
"title": "Python"
}
]
}
]
This is how all skills look like
this.skill_types = [
{"id":8,"title":"Cleaner", checked:false},
{"id":7,"title":"Painter", checked:false},
{"id":6,"title":"Plumber", checked:false},
{"id":5,"title":"Carpenter", checked:false},
{"id":4,"title":"Advisor", checked:false},
{"id":3,"title":"Team Leader", checked:false},
{"id":2,"title":"Management", checked:false},
{"id":1,"title":"Administrator", checked:false}
];
This array contains the IDs of skills that I want to filter
filterArr = [1, 3, 6];
This solution is almost working as expected. It is filtering well based on two criteria together.But not sure how to add condition for second filtering. The second filter should apply only if filterArr is not empty.
return this.items = this.items.filter((thisUser) => {
return thisUser.online_status.toLowerCase().indexOf(onlineStatus.toLowerCase()) > -1 &&
thisUser.skills.some(c => this.filterArr.includes(c.id))
});
The issue I am facing with code above is When there is no skill selected in the filter criteria, I would like to display all users. But it is not working that way. The logic here is to not apply any filter when the size of selected skills (filter condition) is greater than zero. So I tried this way....which looks similar to the way above...but this makes everything worse.
let filteredByStatus = [];
filteredByStatus = this.items.filter((thisUser) => {
return thisUser.online_status.toLowerCase().indexOf(onlineStatus.toLowerCase()) > -1
});
//Condition can be applied if filtering is separated
let filteredBySkills = [];
filteredBySkills = this.items.filter((thisUser) => {
return thisUser.skills.some(c => this.filterArr.includes(c.id))
});
//Expecting to join results from multiple filters
return this.items = filteredByStatus.concat(filteredBySkills);
But this is not working at all. Not sure what wrong is there. I am looking for a solution that enables to join arrays of similar objects without duplicating them.
Don't think you need to join arrays for your filtering. You can use something like rxjs filter.
return from(this.items)
.pipe(
filter(user => {
return user.online_status.toLowerCase().indexOf(onlineStatus.toLowerCase()) > -1
&& user.skills.some(c => filterArr.includes(c.id));
})
);
Or if you like to split it up you can just change it to like:
return from(this.items)
.pipe(
filter(user => user.online_status.toLowerCase().indexOf(onlineStatus.toLowerCase()) > -1),
filter(user => user.skills.some(c => filterArr.includes(c.id)))
);
Stackblitz: https://stackblitz.com/edit/angular-pk3w8b
You can tweak your condition a bit and place !this.filterArr.length in your condition (in terms of OR condition AND with user status) to make your whole condition gets true so that user gets filter.

Angular JS : How to create a Array dynamically by reading a JSON Array

I have a JSON as below
[
{
"id": 1000,
"name": "Open"
},
{
"id": 1000,
"name": "Ravi"
},
{
"id": 1000,
"name": "POOO"
}]
On click of a button I am trying to create a Array by reading all the names from the Array
I have tried as follwoing
var myapp = angular.module('myapp', []);
myapp.controller('FirstCtrl', function($scope)
{
$scope.formData = function()
{
var aa = $scope.tickets.length;
$scope.products = $scope.tickets.name;
alert($scope.products);
};
$scope.tickets = [
{
"id": 1000,
"name": "Open"
},
{
"id": 1000,
"name": "Ravi"
},
{
"id": 1000,
"name": "POOO"
}]
});
Currently i am getting undefined , could you please let me know how to do this
Thanks in advance
http://jsfiddle.net/9fR23/434/
I dont want tradional style using a for loop to read .
Could you please suggest a professional approach .
If you won't to use a loop to read, then you can use Underscore.js.
By using Underscore.js you can do this as below. before that you need to check this link for how use underscore inside angular controllers.
var result = _.map([{ id: 1, name: "vinit"},{ id: 2, name: "jaimin"}], function (v) {
return v.name;
});
alert(JSON.stringify(result));
jsfilddle
You can make a loop to read all data in array and push them to your new array:
$scope.formData = function()
{
$scope.products = [];
var aa = $scope.tickets.length;
angular.forEach($scope.tickets, function(value, key) {
$scope.products.push(value.name);
});
alert($scope.products);
};
Updated fiddle

how to use Immutability helper to update a nested object within an array?

Inside reducer, given a state object:
var state = {
"data": [{
"subset": [{
"id": 1
}, {
"id": 2
}]
}, {
"subset": [{
"id": 10
}, {
"id": 11
}, {
"id": 12
}]
}]
}
As you can see, the data is a nested array, with arrays in each of its elements.
Knowning that action.indexToUpdate will be a index for data, I want to update data[action.indexToUpdate].subset to a new array programmatically. For example, if action.indexToUpdate = 0, then data[0] will be updated from
[{"id":1},{"id":2}]
to
[{"id":4},{"id":5}]
In order to do so, I have:
let newSubset = [{"id":4},{"id":5}]
let newState = update(state.data[action.indexToUpdate], {
subset: {
newSubset,
},
})
But when I executed this, it returns error:
TypeError: value is undefined
on the update founction.
I have been looking at the react ducomentation here: https://facebook.github.io/react/docs/update.html but I couldn't really figure out how to do it. Please advise!
Your update will look like
var obj = {"state" : {
"data": [{
"subset": [{
"id": 1
}, {
"id": 2
}]
}, {
"subset": [{
"id": 10
}, {
"id": 11
}, {
"id": 12
}]
}]
}}
return update(obj, {
"state" : {
"data": {
[action.indexToUpdate]: {
"subset": {
$set: [newSubset]
}
}
}
}
})
In case there are other fields in subset, but you only wish to the change the fields at specific index containing other keys, you would write
return update(obj, {
"state" : {
"data": {
[action.indexToUpdate]: {
"subset": {
[id]: {$merge: newSubset}
}
}
}
}
})

Error in routing with id parameter, link works but displays no data

I am having an issue with retrieving the stored data (within MongoDB) by way of an :id parameter. The link works and takes me to the specified url (./contests/1), but the data doesn't show up. When querying within the mongo CMD with (db.contests.find( {id:1} )) the correct object's data is displayed correctly.
route/contest.js
router.route("/contests/:id")
.get(function(req, res, next) {
Contest.findOne({id: req.params.id}, function(err, contest) {
if(err) {
res.send(err);
}
res.json(contest);
});
service/contestService.js
app.factory("contestService", ["$http", "$resource",
function($http, $resource)
{
var o = {
contests: []
};
function getAll() {
return $http.get("/contests").then(function(res) {
angular.copy(res.data, o.contests);
});
}
function get(id) {
return $resource('/contests/:id');
}
o.getAll = getAll;
o.get = get;
return o;
}]);
})();
controller/contestController.js
var app = angular.module("sportsApp.controllers.contest,["ui.router"]);
app.config(["$stateProvider", function($stateProvider) {
$stateProvider.state("contest", {
parent: "root",
url: "/contests/:id",
views: {
"container#": {
templateUrl: "partials/contests",
controller: "ContestController"
}
}
});
}
]);
app.controller("ContestController", ["$scope","contestService", "$stateParams", function($scope, contestService, $stateParams) {
var contest_id = $stateParams.id;
$scope.contest = contestService.get({id: contest_id});
}]);
})();
Contest Schema
var mongoose = require("mongoose");
var ContestSchema = new mongoose.Schema(
{
id: Number,
tags: String,
matchups: [{
type: mongoose.Schema.Types.ObjectId,
ref: "Matchup"
}],
usersWhoJoined: [{
type: mongoose.Schema.Types.ObjectId,
ref: "User"
}]
});
mongoose.model("Contest", ContestSchema);
Any assistance or advice would be much appreciated due to the fact that I am learning as I go with the MEAN stack and have little to no experience with it.
I am looking to display the specific contest's matchups in which displays two teams and other variables. This is my json file that I mongoimported in order to create the object of the contests collection within MongoDB:
{
"id": 1,
"tags": "NBA",
"matchups": [{
"matchupId": 1,
"selectedTeam": "",
"matchupWinner": "Atlanta",
"nbaTeams": [{
"team": "Portland",
"logo": "stylesheets/nbalogos/Portland-Trail-Blazers-Logo.png"
}, {
"team": "Atlanta",
"logo": "stylesheets/nbalogos/atl-hawks.png"
}]
}, {
"matchupId": 2,
"selectedTeam": "",
"matchupWinner": "Dallas",
"nbaTeams": [{
"team": "Dallas",
"logo": "stylesheets/nbalogos/Dallas-Mavericks.png"
}, {
"team": "Detroit",
"logo": "stylesheets/nbalogos/DET.png"
}]
}, {
"matchupId": 3,
"selectedTeam": "",
"matchupWinner": "Golden State",
"nbaTeams": [{
"team": "Golden State",
"logo": "stylesheets/nbalogos/GSW.png"
}, {
"team": "Memphis",
"logo": "stylesheets/nbalogos/Memphis-Grizzlies.png"
}]
}, {
"matchupId": 4,
"selectedTeam": "",
"matchupWinner": "Oklahoma City",
"nbaTeams": [{
"team": "Oklahoma City",
"logo": "stylesheets/nbalogos/OKC-Thunder.png"
}, {
"team": "Pheonix",
"logo": "stylesheets/nbalogos/Pheonix-Suns.jpg"
}]
}, {
"matchupId": 5,
"selectedTeam": "",
"matchupWinner": "Utah",
"nbaTeams": [{
"team": "Sacremento",
"logo": "stylesheets/nbalogos/Sacremento-Kings.jpg"
}, {
"team": "Utah",
"logo": "stylesheets/nbalogos/Utah-Jazz.jpg"
}]
}]
}
I want to create each contest in this format.
I have no idea what relevance the actual data has to this issue, so let's start with $scope.contest, since there seems to be a problem with the way you're accessing data.
// ContestController
$scope.contest = contestService.get({id: contest_id});
OK, so you're calling the contestService.get method with an object, let's say it's {id: 2}. Let's look at that method and call it with that object.
// contestService
function get(id) {
return $resource('/contests/' + id);
}
If using our dummy data, if you call get({id: 2}), you now have an Angular resource at the URL /contests/[object Object] because your object gets converted into a string. Your method would work if called using the value at the id property of that object, like:
// ContestController
$scope.contest = contestService.get(contest_id);

AngularJS filter on multiple lists of multiple checkboxes

I apologise if this has been answered already, but I'm new to Angular so might have missed it.
I have a need to provide multiple sets of checkbox lists, which need to be combined to create an AND query.
It's on Plunker here http://plnkr.co/OGmGkz22n4J4T8p74yto but enclosed below. At the moment I can select the bottom row and the correct names appear from storeArray, but I cannot work out how to add the Format array into the filter.
I've tried:
<div ng-repeat="store in storeArray | filter:(formatFilter && tillFilter)">
and
<div ng-repeat="store in storeArray | filter:formatFilter:tillFilter">
but they don't work.
Any suggestions please?
var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.formatFilter = function(a) {
for (var fmt in $scope.formatsArray) {
var f = $scope.formatsArray[fmt];
if (f.on && a.format.indexOf(f.name) > -1) {
return true;
}
}
};
$scope.tillFilter = function(a) {
for (var till in $scope.tillsArray) {
var t = $scope.tillsArray[till];
if (t.on && a.tills.indexOf(t.name) > -1) {
return true;
}
}
};
$scope.formatsArray = [{
name: "Super",
on: false
}, {
name: "Express",
on: false
}, {
name: "Other",
on: false
}];
$scope.tillsArray = [{
name: "Main",
on: false
}, {
name: "Service",
on: false
}, {
name: "Petrol",
on: false
}];
$scope.storeArray = [{
"id": "1",
"name": "101",
"format": "Super",
"tills": ["Main", "Service", "Petrol"]
}, {
"id": "2",
"name": "102",
"format": "Express",
"tills": ["Main", "Service"]
}, {
"id": "3",
"name": "103",
"format": "Other",
"tills": ["Main", "Petrol"]
}, {
"id": "4",
"name": "104",
"format": "Super",
"tills": ["Service", "Petrol"]
}];
}
While you can chain filters together like this:
<div ng-repeat="store in storeArray | filter:formatFilter | filter:tillFilter)">
This won't fix your problem since the first filter will do it's job, and filter items out that you may want to include in your second filter. I'm not sure of any way to do an "or" filter. Is there any reason you can't do a custom filter that includes both? I modified your plunker with a custom filter:
http://plnkr.co/edit/han1LFl7toTsSX27b9Q0?p=preview
The code isn't super clean... it does the job. :) You may want to polish it up a bit.

Resources