Get object key in ng-repeat - javascript

If I have an object like the following:
languages = {
"ar":{
"name":"Arabic",
"nativeName":"العربية"
},
"bg":{
"name":"Bulgarian",
"nativeName":"български език"
},
"ca":{
"name":"Catalan; Valencian",
"nativeName":"Català"
}...
}
And I loop through it in a list like so:
<ul>
<li ng-repeat="lang in languages"><a ng-click="select(lang)">{{lang.nativeName}}</a></li>
</ul>
Is there a way to get the object key in the select function without also putting the key in the object itself?
i.e:
languages = {
"ar":{
"name":"Arabic",
"nativeName":"العربية",
"key":"ar"
},
Thanks.

You could do like below:
<ul>
<li ng-repeat="(key, lang) in languages"><a ng-click="select(key)">{{lang.nativeName}}</a></li>
</ul>

Related

Get index of an element from a NodeList

I have a simple list:
<ul id="list">
<li id="item-1">1</li>
<li id="item-2" style="display: none">2</li>
<li id="item-3">3</li>
<li id="item-4">4</li>
<li id="item-5">5</li>
</ul>
And need to get index of a specific item disregarding hidden items.
var list = document.getElementById('list');
var items = list.querySelectorAll('li:not([style*="display: none"])');
I try to convert NodeList in Array:
var list_items = Array.from(items);
But don't known how to run something like that: list_items.indexOf('item-3')
https://codepen.io/marcelo-villela-gusm-o/pen/RwNEVVB?editors=1010
You can make a function to find the id you need in a list you want, passing two parameters, that way you can use this function dynamically.
Based on id, inside the function just need to use .findIndex() that returns the index or -1 if not found.
See here:
var list = document.getElementById('list');
var items = list.querySelectorAll('li:not([style*="display: none"])');
var list_items = Array.from(items);
function getIndexById(idToSearch, list){
//ES6 arrow function syntax
return list.findIndex(elem => elem.id == idToSearch)
//normal syntax
//return list.findIndex(function(elem) {return elem.id == idToSearch})
}
console.log("found at index: ", getIndexById("item-3", list_items))
<ul id="list">
<li id="item-1">1</li>
<li id="item-2" style="display: none">2</li>
<li id="item-3">3</li>
<li id="item-4">4</li>
<li id="item-5">5</li>
</ul>
Not exactly related to the question, but if possible, I would suggest you to change your HTML to remove that inline style of display: none and change it to a class, (e.g: class='hidden'), it would be better for your .querySelector when using :not, for example: li:not(.hidden), since any space in your inline style can break your selector. ("display:none" != "display: none", spot the space)
Maybe like this:
var item = list_items.find(function(item) {
return item.id === "item-3";
});
I would recommend using :not(.hidden) instead of "grepping" for a match on the style tag. Then, simply find the index after casting the NodeList to an array.
For the Vue.js inclined, see this fiddle: https://jsfiddle.net/634ojdq0/
let items = [...document.querySelectorAll('#list li:not(.hidden)')]
let index = items.findIndex(item => item.id == 'item-4')
console.log('item-4 index in visible list is', index)
.hidden {
display: none;
}
<ul id="list">
<li id="item-1">1</li>
<li id="item-2" class="hidden">2</li>
<li id="item-3">3</li>
<li id="item-4">4</li>
<li id="item-5">5</li>
</ul>
Maybe you can use map. First you can create an object with id and value. Then use map function to create array of this object. Then you can access it with foreach, when id = 'item-3'.

Loop through Object in JSX

On a JSX file, I need to loop through two levels of an Object to render the information each inner Array stores. It looks something like: Object > Object > Array
My data is structured this way:
const data = {
group1: {
subgroup1: [{...}, {...},{...}],
...
},
...
}
So I'm trying to acomplish something like this:
return (
<ul>
for (group in data) {
<li>Group Name
<ul>
for(subgroup in group) {
<li>Subgroup Name
<ul>
subgroup.map()
</ul>
</li>
}
</ul>
</li>
}
</ul>
)
I know for loops are not allowed inside a JSX file but converting my object into multiple Arrays doesn't seem right either since I have no idea how many items might be coming form my API.
I solved this using Herohtar suggestion, extracting the key/value of each of the parent Objects in an Array format:
{
Object.entries(data).map(group => (
<ul key={group[0]}>
<li>{group[0]}
<ul>
{
Object.entries(group[1]).map(subgroup => (
<ul key={subgroup[0]}>
<li>{subgroup[0]}
<ul>
{
subgroup[1].map(item => (
<li key={item.code}>{item.name}</li>
)
)
}
</ul>
</li>
</ul>
)
)
}
</ul>
</li>
</ul>
)
)
}
I wish there was a more elegant way of doing this though.

How to display following object in angular5 html file?

In the above screenshot console I have an object with 2 values users and tickers. Again each one is array of values.
Now how to display these values in angular5 html template as specified in above screenshot?
I am trying to use ngFor but it is showing errors.
Suppose this is your data:
public data = {
tickers:[
{id:"1",name:"Ticker Name 1", company:"Company 1"},
{id:"2",name:"Ticker Name 2", company:"comapny 2"}
],
users:[
{id:"1",first_name:"User1 ", last_name:"u1last", email:"user1#test.com"},
{id:"2",first_name:"User2", last_name:"u2last", email:"user2#test.com"},
{id:"3",first_name:"User3", last_name:"u3last", email:"user3#test.com"},
{id:"4",first_name:"User4", last_name:"u4last", email:"user4#test.com"}
]
};
public dataKeys; // This will hold the main Object Keys.
The constructor will look something like this:
constructor() {
this.dataKeys = Object.keys(this.data);
}
Here is the simple HTML that you need to write:
<div *ngFor="let key of dataKeys">
<h3>{{ key }}</h3>
<ul>
<li *ngFor="let d of data[key]">{{d.name || d.first_name}}</li>
</ul>
</div>
Here is the complete working plunker for your case:
Click here to view the Working Solution
you can use like that,
<ul>
<P>users</p>
<li *ngFor="let item of object.users; let i = index">
{{i}}. {{item.frist_name}}
</li>
<P>Tickets</p>
<li *ngFor="let item of object.tickers; let i = index">
{{i}}. {{item.name}}
</li>
</ul>
According to the documentation it should be this:
Users:
<ol>
<li *ngFor="let user of users">{{user.first_name}}</li>
</ol>
Tickets:
<ol>
<li *ngFor="let ticket of tickets">{{ticket.name}}</li>
</ol>
You can use json pipe for debug purpose like this:
{{object |json}}
If you want exactly as in picture, look at this solution. With this case, you don't need to manually write first level property names of object in template for using *ngFor

Angular recursive ng-include while keeping track of recursion depth

I have a situation that is pretty similar to this answer to the question here:
AngularJS ng-include with nested hierarchy
I have some data in the format
$scope.data = {
text: "blah",
comments:
[
{
text: ["blahL11", "blahL12", "blahL13"],
comments: [
{
text: ["blahL111", "blahL112", "blahL113"]
},
{
text: ["blahR111", "blahR112", "blahR113"]
}
]
},
{
text: ["blahR11", "blahR12", "blahR13"]
}
]
};
And I am display it with a recursive ng-include like this:
<ul>
<li>{{data.text}}</li>
<li ng-repeat="item in data.comments" ng-include="'tree'"></li>
</ul>
<script type="text/ng-template" id="tree">
<ul>
<li ng-repeat="text in item.text">{{text}}</li>
<li ng-repeat="item in item.comments" ng-include="'tree'"></li>
</ul>
</script>
http://plnkr.co/edit/8swLos2V6QRz6ct6GDGb?p=info
However, I would like to somehow keep track of the depth of the recursion as well. So that instead of simply displaying:
-blah
-blahL11
-blahL12
-blahL13
-blahL111
It could display
-1. blah
-2. blahL11
-2. blahL12
-2. blahL13
-3. blahL111
Without me modifying the data structure (as the depth is only really for display?). Can I insert a variable into the ng-include, is there some sort of recursive $index I can use?
You can do this using ng-init. This will assign a value to the new scope when it's created, which you can do by refering to a value in the old scope and incrementing it.
plnkr demo
<li ng-repeat="item in item.comments" ng-include="'tree'" ng-init="depth = depth + 1"></li>

Identify unique data attributes

I am creating a jquery plugin that will sort a list based on data attributes:
<ul class="reorder">
<li data-rating="1" data-category="3">Rating 1 - Category 3</li>
<li data-rating="5" data-category="1">Rating 5 - Category 1</li>
<li data-rating="2" data-category="2">Rating 2 - Category 2</li>
<li data-rating="7" data-category="1">Rating 7 - Category 1</li>
<li data-rating="21" data-category="3">Rating 21 - Category 3</li>
<li data-rating="19" data-category="2">Rating 19 - Category 2</li>
</ul>
As I don't know how many data attributes will be added, I want to be able to loop through the list and identify unique data attributes (NOT the value of those attributes) to create a set of links:
<ul class="reorder-nav">
<li>Sort by rating</li>
<li>Sort by category</li>
</ul>
My basic idea is to loop through each list item and create an array of data attributes, then filter that array for unique attributes.
I can create an array of all data attributes with .data() but other than that I'm a bit stuck so would appreciate any suggestions.
You can do something like this to extract the data-x attribute names :
var uniqueAttrs = {};
$('.reorder li').each(function(){
$.each(this.attributes, function(_,a){
if (a.name.indexOf('data-')===0) {
uniqueAttrs[a.name.slice(5)] = 1;
}
});
});
Then you can iterate over the keys of uniqueAttrs :
for (var attr in uniqueAttrs) {
console.log(attr); // for example "sort" or "ranking"
}
If you can afford to support a limited set of browsers, you can simplify the loop by using dataset instead of attributes.

Categories

Resources