Angular, filtering down a json object - javascript

I have a big json object I am using to control a cascading select list that I am trying to filter down to prepare for sending to the server.
The structure looks something like this -
Accounts[{name:account1, id:1, selected:false, schools:[{name:school1, id:2,selected:true}]}]
(With multiple accounts with multiple schools in each, keeping it simple for example purposes)
What I am trying to do is put it through some maps/filters and achieve an array of ids of schools that have the key of selected = true. So my attempt is to filter down by first all schools, then by schools that have selected true, then just the id's of those schools.
So here is my attempt -
$scope.schooIDsForSave = $scope.accountTreeHere.filter( function(obj){
return obj.schools;
}).filter( function(obj){
return obj.selected;
}).map(function(obj){
return obj.id;
});
This is only returning 1 ID so I'm getting something wrong here. I think I have something wrong with my usage of map/filter as I am still vey new to it. Any insight to point me in the right direction would be much appreciated! Thanks for reading.

Given structure
var schools = [{
name: 'account1',
id: 1,
selected: false,
schools: [{
name: 'school1',
id: 2,
selected: true
}]
}, {
name: 'account2',
id: 2,
selected: false,
schools: [{
name: 'school2',
id: 3,
selected: false
}]
}];
Try
var ids = schools.map(function(v) {
return v.schools;
}).reduce(function(a, b) {
return a.concat(b);
}).filter(function(v) {
return v.selected;
}).map(function(v) {
return v.id;
});

Related

Javascript Array Push and Display

I am doing a Laravel project with editable inline with select option however I want I manage to query the brands and I want to display the array after I push it in the source. Please help
var brand = [];
data_brand.forEach(function(element) {
var branddetails = {value: element.id, text: element.brand_name};
brand.push(branddetails);
});
$(function(){
$('#brand').editable({
value: 2,
source: [
//I want to output like this {value: 1, text: 'Active'},
brand.values() // this code does not work
]
});
});
This should work:
source: brand.map(item => item)
or simply:
source: brand
brand is an array and you since source also expecting the array, You can try like this
source: [...brand]
In order to display the array elements, use loop.
Example-
let branddetails = [{value: 1, text: "something" }];
branddetails.forEach(brand => console.log(brand));
-- Edit --
Instead of creating array and then getting the pushed element, you can directly add the element itself in the source array.
let branddetails;
data_brand.forEach(function (element) {
branddetails = { value: element.id, text: element.brand_name };
});
$(function () {
$('#brand').editable({
value: 2,
source: [
branddetails
]
});
});

How to weight items in a fuzzy search

Using Fuse.js, I need to weight individual item for a better ranking in search results. For instance, how do I make sure "Paris France" has the biggest score for a "Paris" query with the data below?
places = [{
name: 'Paris, France'
weigth: 10
},{
name: 'Paris, Ontario'
weigth: 2
},
{
name: 'Paris, Texas'
weigth: 1
}]
As far as I am aware, there are no methods built into Fuse.js to do this. The weight property is meant to be applied to properties which are being searched (in the options object), rather than to the object that is being searched (as seen in the example here.
What I might suggest is writing a function to sort this yourself. So once you get your results array back, after the search, perform an Array.sort() on it yourself (documentation here).
For example...
//Your places object
var places = [
{
name: 'Paris, Texas',
weight: 2
},
{
name: 'Paris, France',
weight: 10
},
{
name: 'Paris, Texas',
weight: 1
}
];
//Your search options
var options = {
keys: [
"name"
]
};
var fuse = new Fuse(places, options); // "list" is the item array
var result = fuse.search("Paris");
//Once you have got this result, perform your own sort on it:
result.sort(function(a, b) {
return b.weight - a.weight;
});
console.log('Your sorted results:');
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/fuse.js/3.1.0/fuse.min.js"></script>

Extracting data from a complex array without lots of FOR loops

I have a fairly complex array generated from Google's natural language API. I feed it a paragraph of text and out comes lots of language information regarding such paragraph.
My end goal is to find "key words" from this paragraph, so, to achieve this I want to put all the "entities" into a flat array, count the duplicates, and then consider words with the highest amount of duplicates to be "key words". If it doesn't find any then I'll cherry pick words from entities I consider most significant.
I already know the entities that could exist:
var entities = [
'art',
'events',
'goods',
'organizations',
'other',
'people',
'places',
'unknown'
];
Here is an example structure of the array I'm working with.
input = [
{
language: {
entities: {
people: [
{
name: "Paul",
type: "Person",
},
{
name: "Paul",
type: "Person",
},
],
goods: [
{
name: "car",
type: "Consumer_good",
}
], //etc
}
}
}
];
output = ["Paul", "Paul", "car"...];
My question is - what is the best way to convert my initial array into a flat array to then find the duplicates without using a whole bunch of FOR loops?
There is no way around loops or array functions if you work with dynamic input data.
You can access all the values using this format:
input[0]["language"]["entities"]["people"][0].name
input = [
{
language: {
entities: {
people: [
{
name: "Paul",
type: "Person",
},
{
name: "Paul",
type: "Person",
},
],
goods: [
{
name: "car",
type: "Consumer_good",
}
], //etc
}
}
}
];
console.log(input[0]["language"]["entities"]["people"][0].name);
Then you could do something like this:
for (var entry in input[0]["language"]["entities"]) {
console.log(entry);
}
OR, if I understood you wrong,
You can use this to turn the javascript Object into an array using this (requires jquery):
var myObj = {
1: [1, 2, 3],
2: [4, 5, 6]
};
var array = $.map(myObj, function(value, index) {
return [value];
});
console.log(array[0][0]);
console.log(array[0]);
console.log(array);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
This will output
1
[1, 2, 3]
[[1,2,3],[4,5,6]]
You could iterate through input.language.entities in a recursive way and collect all the .name properties into an array. Then you have only one for loop :-).
After doing that, you can iterate through it to find the duplicates. If you sort it alphabetical before it is easier (if two or more consecutive entries are equal, there are duplicates).
But it could be a bit dangerous if google changes the api or if it delivers crap data because of a malfunction.
Isn't input.language.entities already flat enough to work with it?
I ended up doing something like this. It's not pretty but it gets the job done.
var result = [];
var known_entities = ['art','events','goods','organizations','other','people','places','unknown'];
for(i=0; i < known_entities.length; i++){
var entity = known_entities[i];
if(language.entities[entity]){
for(var j in language.entities[entity]){
var word = language.entities[entity][j].name
result.key_words.push(word);
}
}
}

How to create json array with the inner array in javascript and access it

I want to create an object with an array property which looks like this:
var arrayOfUsers = {
id: "some user id",
username : "some names",
roles : [array with roles]
}
And i would like to access an element by id, something like, arrayOfUsers['some id']['roles'];
I am new to json. I've tried different ways, but always ended up with bunch of errors.
First, this is a JavaScript object. JSON is a string representation of JavaScript objects.
Second, it's important to know the difference between an object and an array. In general, consider Objects to be defined with curly braces { } and Arrays with braces [ ]
Values in Arrays are accessed by their index with the arr[index] syntax while objects use obj[key] syntax to access the value assigned to some key on the object.
For your scenario, I'd avoid using arrays, because you want to be able to access objects by key, not by index.
var users = {
"some user id": {
username : "some names",
roles : {
"some role id": {
name: "role name"
}
}
}
};
In reality, this isn't a very effective data structure, because you'd likely want to deal with arrays for looping, rendering, etc, but to answer your question about being able to index by the Id of user and role, this is how your data would have to be structured.
Here is how you declare:
var currentUser,
currentRole,
arrayOfUsers = {
id: 1,
username: "Sample Value",
roles: [{
roleId: 1,
name: "Admin"
},
{
roleId: 2,
name: "Cashier"
}]
};
This is how you access it:
for (var i = arrayOfUsers.length; i--;) {
currentUser = arrayOfUsers[i];
for (var x = currentUser.roles.length; x--;) {
currentRole = currentUser.roles[x];
console.log("ID=" + currentRole.id + "Name=" + currentRole.name);
}
}
First, you have to make difference between array which defined by [], and Objects, by {}.
If you want to make an array of JSON, you can do the following :
var arrayRoles = [{
idRole: 1,
type: 'admin'
}, {
idRole: 2,
type: 'user'
}];
var userArray = [{
id: 1,
username: 'toto',
roles: arrayRoles
}, {
id: 2,
username: 'titi',
roles: arrayRoles
}, {
id: 3,
username: 'toto',
roles: arrayRoles
}];
Then, if you want to iterate over all your data, you can do it by using forEach loop, which tends to be more elegant :
userArray.forEach(function(elm){
//Our roles array
var roles = elm.roles;
//For all item in roles array
roles.forEach(function(value){
//display type of role, for example.
console.log(value.type);
});
});
But if you want to search a specific item in your JSON array, you can use filter method, by using high order function.
function filterBy(key, filter){
return function(elm){
return elm[key] === filter;
}
}
Then, you can apply this function to your filter, by passing specific field and value, and it will return an array of results :
var filtered = userArray.filter(filterBy('username', 'toto'));
//Display '1'
console.log(filtered[0].id);
//Display '3'
console.log(filtered[1].id);

Filter response object based on an array of whitelisted ids

How to Filter a response object based on an array of whitelisted ids?
I've a working version but i don't like the nested forEach here and i wonder if there is a way to improve it?!
function WhitelistCtrl($scope) {
var visible = [];
var whitelist = [123, 456]; // items to be visible
var response = [{
id: 123,
name: 'my object #1'
}, {
id: 456,
name: 'my object #2'
}, {
id: 789,
name: 'my object #3'
}];
angular.forEach(whitelist, function (id) {
angular.forEach(response, function (item) {
if (id === item.id) {
visible.push(item);
}
});
});
}
Here is a JSFiddle to play with: http://jsfiddle.net/gearsdigital/rv6vq2L7/
I'm not much familiar with Anglar ForEeach but you can achive this using native javascript filter like bellow
visible = response.filter(function(item){
return (whitelist.indexOf(item.id) > -1);
})
DEMO
NOTE:- IE8 doesn't supports .filter.

Categories