How to find values from another JSON object - javascript

I have set of json objects.
Languages
User Details
User Details have the languages field - which have more than 1 values.
Here is my sample json
$scope.languages = [
{id: 1, text: 'English'},
{id: 2, text: 'French'},
{id: 3, text: 'Hindi'},
{id: 4, text: 'Telugu'}
];
$scope.users = [{name: 'first user', status: 1,language:"1"},
{name: 'second user', status: 2,language:"1,2"},
{name: 'third user', status: 3,language:"1,3,4"}];
In my view i want to list the user name and languages.
<li ng-repeat="user in users">{{user.name}} - {{testString}}</li>
I know to do for single value. But for multiple values. I have the logic but i don't know how to implement. I am thinking that. First i have to split the user language string and change into array and then find the index of the language id and then return the language text.
I have the code to return language name from ID.
var foundItem = $filter('filter')($scope.languages, { id: 3 }, true)[0];
var index = $scope.languages.indexOf(foundItem );
$scope.result = $scope.languages[index].text;
So now the problem is how to print the languages next to the user name?
I tried like this
$scope.testString = function() {
return "return test string";
}
{{testString}}
But its not working. If this works we can pass the langugae codes as parameter and i can add the search code inside the testString function.
Thanks

testString is a function so you cannot use it like {{testString}}, you have to call that function {{testString()}}
You can simplify your code like this.
$scope.getLanguages = function (langs) {
var l = [];
angular.forEach(langs.split(','), function (lang) {
l.push(findLanguageTextById(parseInt(lang)));
})
return l.join(', ');
}
function findLanguageTextById (langId) {
for(var i = 0;i<$scope.languages.length;i++) {
if ($scope.languages[i].id == langId) {
return $scope.languages[i].text;
}
}
}
I have created a working demo for your problem take a look.
http://plnkr.co/edit/Cdl8y58IExoVSZV6lp76?p=preview

I think you are not calling the function,
$scope.testString = (function() {
return "return test string";
})();

Related

Having issue with getting value from object variable. No errors showing

I created an array called animals containing two objects. I want to get a value from the name variable in the object animals and insert that value in a return statement in the map method. I used ${} to access the variable.
const Animals = [{
name: "Lion",
type: "Carnivore",
},
{
name: "Cow",
type: "Herbivore",
},
];
window.addEventListener("DOMContentLoaded", function() {
let display = Animals.map(function(item) {
return '<h1>${item.name}</h1>';
});
console.log(display);
});
Now I'm supposed to get in the console an array of two items containing the values of the variables -- the result should look like this ['<h1>Lion</h1>', '<h1>Cow</h1>']. But instead I get this ['<h1>${item.name}</h1>', '<h1>${item.name}</h1>']. As you can clearly see, for some reason the ${} was unable to access the variable and get the value. I don't know why this's happening. Console log shows no errors. Plz help me resolve this issue. Thanks in advance.
Check in your code instead of:
'<h1>${item.name}</h1>'
Should be:
`<h1>${item.name}</h1>`
Here is the documentation for Template literals (Template strings)
Demo:
const Animals = [{
name: "Lion",
type: "Carnivore",
},
{
name: "Cow",
type: "Herbivore",
},
]
const display = Animals.map(({ name }) => `<h1>${name}</h1>`)
console.log(display)
Variables inside ${...} structures are template/string literals syntax but in order for them to work they need to be enclosed with backticks instead of single/double quotes.
const animals=[{name:"Lion",type:"Carnivore"},{name:"Cow",type:"Herbivore"}];
window.addEventListener("DOMContentLoaded", function() {
const display = animals.map(function(item) {
return `<h1>${item.name}</h1>`;
});
console.log(display);
});
const Animals = [{
name: "Lion",
type: "Carnivore",
},
{
name: "Cow",
type: "Herbivore",
},
];
window.addEventListener("DOMContentLoaded", function() {
let display = Animals.map(function(item) {
return '<h1>'+item.name+'</h1>';
// return `<h1>${item.name}</h1>`;
});
console.log(display);
});

Vue computed property changes the data object

I have basically this structure for my data (this.terms):
{
name: 'First Category',
posts: [
{
name: 'Jim James',
tags: [
'nice', 'friendly'
]
},
{
name: 'Bob Ross',
tags: [
'nice', 'talkative'
]
}
]
},
{
name: 'Second Category',
posts: [
{
name: 'Snake Pliskin',
tags: [
'mean', 'hungry'
]
},
{
name: 'Hugo Weaving',
tags: [
'mean', 'angry'
]
}
]
}
I then output computed results so people can filter this.terms by tags.
computed: {
filteredTerms: function() {
let self = this;
let terms = this.terms; // copy original data to new var
if(this.search.tags) {
return terms.filter((term) => {
let updated_term = {}; // copy term to new empty object: This doesn't actually help or fix the problem, but I left it here to show what I've tried.
updated_term = term;
let updated_posts = term.posts.filter((post) => {
if (post.tags.includes(self.search.tags)) {
return post;
}
});
if (updated_posts.length) {
updated_term.posts = updated_posts; // now this.terms is changed even though I'm filtering a copy of it
return updated_term;
}
});
} else {
return this.terms; // should return the original, unmanipulated data
}
}
},
filteredTerms() returns categories with only the matching posts inside it. So a search for "angry" returns just "Second Category" with just "Hugo Weaving" listed.
The problem is, running the computed function changes Second Category in this.terms instead of just in the copy of it (terms) in that function. It no longer contains Snake Pliskin. I've narrowed it down to updated_term.posts = updated_posts. That line seems to also change this.terms. The only thing that I can do is reset the entire data object and start over. This is less than ideal, because it would be loading stuff all the time. I need this.terms to load initially, and remain untouched so I can revert to it after someone clears their search criterea.
I've tried using lodash versions of filter and includes (though I didn't really expect that to make a difference). I've tried using a more complicated way with for loops and .push() instead of filters.
What am I missing? Thanks for taking the time to look at this.
Try to clone the object not to reference it, you should do something like :
let terms = [];
Object.assign(terms,this.terms);
let terms = this.terms;
This does not copy an array, it just holds a reference to this.terms. The reason is because JS objects and arrays are reference types. This is a helpful video: https://www.youtube.com/watch?v=9ooYYRLdg_g
Anyways, copy the array using this.terms.slice(). If it's an object, you can use {...this.terms}.
I updated my compute function with this:
let terms = [];
for (let i = 0; i < this.terms.length; i++) {
const term = this.copyObj(this.terms[i]);
terms.push(term);
}
and made a method (this.copyObj()) so I can use it elsewhere. It looks like this:
copyObj: function (src) {
return Object.assign({}, src);
}

Javascript using filter/includes on an array of objects

What is the best way to filter out data that exists within an object?
I was able to do use the below code when data was just an array of values but now I need to filter out any data where the item.QID exists in my array of objects.
Data Obj:
var data = [{
QID: 'ABC123',
Name: 'Joe'
},
{
QID: 'DEF456',
Name: 'Bob
}]
Snippet:
// I don't want to include data if this QID is in my object
this.employees = emp.filter(item =>!this.data.includes(item.QID));
From what I understand, includes only works on an array so I need to treat all of the QID values in my object as an array.
Desired Outcome: (assuming item.QID = ABC123)
this.employees = emp.filter(item =>!this.data.includes('ABC123'));
Result:
var data = [{
QID: 'DEF456',
Name: 'Bob'
}]
UPDATE:
Apologies, I left some things a little unclear trying to only include the necessary stuff.
// People Search
this.peopleSearchSub = this.typeahead
.distinctUntilChanged()
.debounceTime(200)
.switchMap(term => this._mapsService.loadEmployees(term))
.subscribe(emp => {
// Exclude all of the current owners
this.employees = emp.filter((item) => item.QID !== this.data.QID);
}, (err) => {
this.employees = [];
});
The above code is what I am working with. data is an object of users I want to exclude from my type-ahead results by filtering them out.
The question is a little ambiguous, but my understanding (correct me if I'm wrong), is that you want to remove all items from a list emp that have the same QID as any item in another list data?
If that's the case, try:
this.employees = emp.filter(item => !this.data.some(d => d.QID === item.QID))
some is an array method that returns true if it's callback is true for any of the arrays elements. So in this case, some(d => d.QID === item.QID) would be true if ANY of the elements of the list data have the same QID as item.
Try Object#hasOwnProperty()
this.employees = emp.filter(item =>item.hasOwnProperty('QID'));
You can use a for ... in to loop through and filter out what you want:
const data = [{
QID: 'ABC123',
Name: 'Joe'
},
{
QID: 'DEF456',
Name: 'Bob'
}]
let newData = [];
let filterValue = 'ABC123';
for (let value in data) {
if (data[value].QID !== filterValue) {
newData.push(data[value]);
}
}
newData will be your new filtered array in this case
You can use an es6 .filter for that. I also added a couple of elements showing the filtered list and an input to allow changing of the filtered value. This list will update on the click of the button.
const data = [{
QID: 'ABC123',
Name: 'Joe'
},
{
QID: 'DEF456',
Name: 'Bob'
}]
displayData(data);
function displayData(arr) {
let str = '';
document.getElementById('filterList').innerHTML = '';
arr.forEach((i) => { str += "<li>" + i.QID + ": " + i.Name + "</li>"})
document.getElementById('filterList').innerHTML = str;
}
function filterData() {
let filterValue = document.getElementById('filterInput').value;
filterText (filterValue);
}
function filterText (filterValue) {
let newArr = data.filter((n) => n.QID !== filterValue);
displayData(newArr)
}
<input id="filterInput" type="text" value="ABC123" />
<button type ="button" onclick="filterData()">Filter</button>
<hr/>
<ul id="filterList"><ul>

Insert values in to an object from loop

I'm trying to create a script that will insert some values in to an object.
I basically want to end up with a series of objects that would look something like this -
myObj.data.person[0].name = 'name 1';
myObj.data.person[1].name = 'name 2';
myObj.data.person[2].name = 'name 3';
etc
Here is my object which contains an array of objects.
var addressBook = {
data: [
person = {
name: '',
address: ''
}
]
}
And a for loop to insert repeating information.
for (i=0; i < 10; i++)
{
myObj.data.person[i] = {name: 'Joe Bloggs', address: 'Main Street'};
console.log(myObj.data.person.name);
}
Whenever I run this code I get the following error -
Uncaught TypeError: Cannot set property 'person' of undefined at <anonymous>:14:24
So, the question is where am I going wrong ? And furthermore would this be considered the right way to go about creating a list of Objects (e.g. Person 1, Person 2 etc)?
(I'm ultimately thinking of how I can create something like a Person constructor and use a loop to create multiple Person objects).
Thanks,
Please try to change your object notation in following way
var addressBook = {
data: [{
name: '',
address: ''
},
{
name: 'Roshan',
address: ''
},
{
name: 'Roshan1',
address: ''
}
]
}
try this :
myObj.data[i].person = 'John';
myObj.data[i].address = 'NYC';
See this Answer as addendum to isetty ravitejakumar's Answer
You should consider writing a prototype / class for your usecase.
In this case you could keep better track of your data.
maybe something like this:
var AddressBook = {},
Person = {};
(function() {
AddressBook.prototype = {
data: [],
add: function(person) {
this.data.push(person);
}
};
Person = function(name, address) {
this.name = name;
this.address = address;
}
Person.prototype = {
name,
address
};
})();

Set value of a property where the property name is dynamic, AND contains a '.'

I have some code which works with a set of data which has come from the server.
var data = [
{ Id: 1, Opened: false, Message: {
{ Subject: 'A message', Body: '....', Date: '2015-06-21T17:35:15' },
},
{ Id: 2, Opened: true, Message: {
{ Subject: 'A message', Body: '....', Date: '2015-05-21T17:35:15' },
}
];
I don't know that the date is going to be under the property Message.Date, as it depends on what the server returns. However, I will always have a list of the fields for data item. Using this example, I'll have something like this:
var fields = [
{id: 1, name: 'Field', type: 'varchar'},
{id: 2, name: 'Opened', type: 'bool'},
{id: 3, name: 'Message.Subject', type: 'varchar'},
{id: 4, name: 'Message.Body', type: 'varchar'},
{id: 5, name: 'Message.Date', type: 'date'},
];
I want to transform the Date property to be a Date object.
Assuming that fields and data have come from the result of an AJAX call, then my code looks something like this...:
$.each(response.fields, function(idx,field){
var dataItems = response.data;
$.each(dataItems, function(rowIdx, rowItem){
if(field.type == 'date'){
dataItems[rowIdx][field.name] = new Date(dataItems[rowIdx][field.name]);
}
});
});
This doesn't work, because I end up trying to access the property named 'Message.Date' of the object, rather than the 'Date' property of the 'Message' property of the object.
I've been doing something like this to handle it so far:
var date = dataItems[rowIdx];
var fieldPropertyLabelSplit = field.propertyLabel.split('.');
for (var i = 0; i < fieldPropertyLabelSplit.length; ++i) {
date = date[fieldPropertyLabelSplit[i]];
}
dataItems[rIdx][field.propertyLabel] = new Date(date);
This way, new Date(date) is OK, but I end up with A instead of B...:
A: B:
{ Message.Date: _date_ }; { Message: { Date: _date _ }};
The only way I've found to get this to work as I'd like is by using eval...
var pN = 'dataItems[rIdx]';
for (var i = 0; i < fieldPropertyLabelSplit.length; ++i) {
pN += '["' + fieldPropertyLabelSplit[i] + '"]';
}
eval(pN +'= new Date(date);');
Are there any libraries or simple functionality I've missed which can handle this sort of use-case? Is this appropriate use of eval? Unfortunately, I have no control server-side, and I end up passing this result to a third-party component which I can't change either.
replace you iterating solution with:
var date = dataItems[rowIdx];
var fieldPropertyLabelSplit = field.propertyLabel.split('.');
for (var i = 0; i < fieldPropertyLabelSplit.length - 1; ++i) {
date = date[fieldPropertyLabelSplit[i]];
}
date[fieldPropertyLabelSplit[i]] = new Date(date[fieldPropertyLabelSplit[i]]);
That way, date points to the last object before the actual value, and i is the index in the array of the last name. When you set the value like this, you maintain your object structure.

Categories