How to ng-repeat childs in 'ng-repeated divs'? - html

I want to create a list of items with subitems. The items and the subitems are listed in arrays like this:
items=[firstItem,secondItem,thirdItem,...]
and
subitems=[{"name":"firstSubitem1","name":"secondSubitem1",...},{"name":"firstSubItem2","name":"secondSubItem2"},...]
So I've set up this html code:
<body>
<div ng-app="" ng-init="items=[firstItem,secondItem,thirdItem,...],subitems=[{"name":"firstSubitem1","name":"secondSubitem1",...},{"name":"firstSubItem2","name":"secondSubItem2"},...]">
<div ng-repeat="itemNames in items" id="item{{$index}}">{{itemNames}}</div>
</div>
</body>
But that only outputs the list if items, and i want to make a list of items (divs) that have subitems (paragraphs). So the output that I want to create is this:
<body>
<div (...) id="item0">
firstItem
<p>firstSubitem1</p>
<p>secondSubitem1</p>
<p>...</p>
</div>
<div (...) id="item1">
secondItem
<p>firstSubitem2</p>
<p>...</p>
</div>
<div (...) id="item2">
...
</div>
</body>
So how can I make it so that will be the output?

You need to restructure your data as following:
items = [{
title: firstItem,
subitems: [firstSubitem1, secondSubitem1, ...]
}, {
title: secondItem,
subitems: [firstSubitem2, secondSubitem2, ...]
}....]
And html to be as follows:
<div ng-repeat="item in items" id="item.title{{$index}}">{{item.title}}
<p ng-repeat="subitem in item.subitems">{{subitem}}</p>
</div>

If you insist on your data structure, use $index from the outer loop:
<body>
<div ng-app="" ng-init="items=[firstItem,secondItem,thirdItem,...],subitems=[{firstSubitem1,secondSubitem1,...},{firstSubItem2,secondSubItem2},...]">
<div ng-repeat="itemNames in items" id="item{{$index}}">
{{itemNames}}
<p data-ng-repeat="(key, value) in subitems[$index]"> {{ value }}</p>
</div>
</div>

Related

How can I get the ID of div inside a div wrapper. Jquery

I have a div that looks like this:
<div id="data" class="grid grid-cols-2">
</div>
and I have a function that can append in data div:
function loadStaticBar(data) {
let pl_name= `bar-${data.title.replace(/\s+/g, '-').toLowerCase()}`
$('#data').append(`
<div class="flex flex-col" id="${pl_name}-wrapper">
<div class="static barchart" id="${pl_name}-plot">
</div>
</div>
`)
}
The content of loadStaticBar(data) is a key and value it's a details for charts:
{id: 453, title: 'Bar Chart Example', select: 'bar-form', xtitle: 'Values', ytitle: 'Date', …}
Now, I'm trying to get all the IDs with the class static. I have tried:
$('#data').find('.static')
And I get S.fn.init [prevObject: S.fn.init(1)] inside of this are bunch of information. How can I get the IDs of the div that containing static class like this.
ids = [line-plot, bar-plot]
The answer to the updated question could be:
function loadStaticBar(data) {
let pl_name= `bar-${data.title.replace(/\s+/g, '-').toLowerCase()}`
$('#data').append(`
<div class="flex flex-col" id="${pl_name}-wrapper">
<div class="static barchart" id="${pl_name}-plot">
</div>
</div>
`)
}
const data={id: 453, title: 'Bar Chart Example', select: 'bar-form', xtitle: 'Values', ytitle: 'Date'};
$(function(){
loadStaticBar(data); // create the divs first !!!
const ids=$("#data .static").get().map(el=>el.id);
console.log(ids);
});
<script src="https://code.jquery.com/jquery-3.6.1.min.js"></script>
<div id="data" class="grid grid-cols-2">
</div>
As you want to receive a "proper" array instead of a jQuery object it makes sense to .get() the selected DOM elements first and then .map() them using the standard Array-method.
Incidentally, you can solve the originally posted question also without jQuery:
document.addEventListener("DOMContentLoaded", function () {
const ids=[...document.querySelectorAll("#data .static")].map(el=>el.id);
console.log(ids);
});
<div id="data" class="grid grid-cols-2">
<div class="flex flex-col" id="line-wrapper">
<div class="static linechart" id="line-plot">
</div>
</div>
<div class="flex flex-col" id="bar-wrapper">
<div class="static barchart" id="bar-plot">
</div>
</div>
</div>

Vue, changing the name of an input via list item click

I have an input that I'm using in relation two an unordered list with two list items, which is in place, but I"m trying to figure out how I can change the input name/id with the click of one of the list items.
The items are not links or buttons, so I just want to be able to click the item text and if 'Public' is clicked, the input name would become public, if 'Internal' is clicked I would want the input name to be internal
I'm using Vue which may have some better options, but basically I just want to send the name of the input later on in an ajax call and I only want the name to be determined by the click of a list item potentially with a default.
What is the best way to achieve this with Vue being used?
<div class="row notesInput">
<div class="col-lg-12">
<div class="tabs">
<ul style="border-bottom:none !important; text-decoration:none">
<li>Public</li>
<li>Internal</li>
</ul>
</div>
<div>
<input type="text" name="public">
</div>
</div>
</div>
First step: use component data to your advantage
You can simply store the desired input name attribute in the component data, e.g. inputName. Then, use v-on to bind a click event listener to your elements, so that whenever they are clicked, you invoke a method that updates the inputData property of your component.
new Vue({
el: '#app',
data: {
inputName: '',
},
methods: {
setInputName(str) {
this.inputName = str;
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="row notesInput">
<div class="col-lg-12">
<div class="tabs">
<ul style="border-bottom:none !important; text-decoration:none">
<li v-on:click="setInputName('public')">Public</li>
<li v-on:click="setInputName('internal')">Internal</li>
</ul>
</div>
<div>
<input type="text" v-bind:name="inputName">
<br />
Input name attribute is: {{ inputName }}
</div>
</div>
</div>
</div>
Better: Use v-for to generate list items dynamically
If you don't want the manually provide the argument to the method, there's an easier way: you simply create a list of allowed names in the component data, too, and use v-for to generate the list dynamically:
new Vue({
el: '#app',
data: {
inputName: '',
allowedNames: ['Public', 'Internal']
},
methods: {
setInputName(str) {
this.inputName = str.toLowerCase();
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="row notesInput">
<div class="col-lg-12">
<div class="tabs">
<ul style="border-bottom:none !important; text-decoration:none">
<li
v-for="(allowedName, i) in allowedNames"
v-bind:key="i"
v-on:click="setInputName(allowedName)">
{{ allowedName }}
</li>
</ul>
</div>
<div>
<input type="text" v-bind:name="inputName">
<br />
Input name attribute is: {{ inputName }}
</div>
</div>
</div>
</div>
Even better: if there is no one-to-one correspondance between list item text and the desired name attribute
This can be useful in the case when, for example, you want the text to read Public but the name attribute to be another value. Instead of an array of strings, you can use an array of objects:
new Vue({
el: '#app',
data: {
inputName: '',
allowedNames: [{
label: 'Public (or any other arbitrary text you like)',
name: 'public'
}, {
label: 'Internal (or any other arbitrary text you like)',
name: 'internal',
}]
},
methods: {
setInputName(str) {
this.inputName = str;
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="row notesInput">
<div class="col-lg-12">
<div class="tabs">
<ul style="border-bottom:none !important; text-decoration:none">
<li
v-for="(allowedName, i) in allowedNames"
v-bind:key="i"
v-on:click="setInputName(allowedName.name)">
{{ allowedName.label }}
</li>
</ul>
</div>
<div>
<input type="text" v-bind:name="inputName">
<br />
Input name attribute is: {{ inputName }}
</div>
</div>
</div>
</div>

Create mixed list of lists with empty and filled sections?

With BeautifulSoup, I am trying to create a list of lists, which returns empty lists as well as variables in the sequence they appear, using this example of HTML code below...
[<div class="Stats">
</div>
<div class="Stats">
</div>
<div class="Stats">
</div>
<div class="Stats">
</div>
<div class="Stats">
</div>
<div class="Stats">
<div class="Stats__x">
<!--
-->C<!--
--></div>
</div>
<div class="Stats">
</div>
<div class="Stats">
</div>
<div class="Stats">
</div>]
My current code attempts are getting...
[['C']]
The result I would like to get is...
[[], [], [], [], [], ['C'], [], [], []]
I have tried many ways, creating empty list of lists by finding the number of divs x = len(stats = soup.find_all("div", {"class": "Stats"}), and then with for loops attempting to append an element if it exists and leave the empty list in place if it doesn't.
hList = []
for each in stats:
for each2 in each.find_all("div", {"class":"Stats__x"}):
hList.append(each2.text.split())
I probably need to perform some type of index assignment but I can't figure it out.
Thanks.
First I search all div with class="Stats" and inside every div I search one div with class="Stats__x". If I get None then I change it into []
data = '''<div class="Stats"></div>
<div class="Stats"></div>
<div class="Stats"></div>
<div class="Stats"></div>
<div class="Stats"></div>
<div class="Stats">
<div class="Stats__x">
<!--
-->C<!--
--></div>
</div>
<div class="Stats"></div>
<div class="Stats"></div>
<div class="Stats"></div>'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(data, 'html.parser')
result = []
for div in soup.find_all("div", {"class": "Stats"}):
item = div.find("div", {"class": "Stats__x"}):
if item:
result.append( item.text.split() )
#result.append( [item.text.strip()] )
else:
result.append( [] )
print(result)

*ngfor split data of an array

I consume a external JSON API with this array.
temperature_mean: [ 16.94,19.9,19.13,15.22,15.52,15.62,12.47 ],
I want to split this array into seperated objects with an *ngFor loop:
<div class="card">
<h2>Temperature</h2>
<div *ngFor="let temp of cityTemperature">
{{cityTemperature}}
</div>
</div>
That's what I got back:
But I want on each line only one object. How can I do that and seperate this loop?
You need to change your html to:
<div class="card">
<h2>Temperature</h2>
<div *ngFor="let temp of cityTemperature">
{{ temp }}
</div>
</div>

Double ng-repeat to flatten out nested object

I have a use in case which I had solved up 'til now with ng-repeat-start. It currently looks like this:
Controller
$scope.providers = [
'Site Hosting',
'Best Hosting',
'Fantastic Hosting'
];
$scope.providerColumns = {
price: {
text: 'Price',
exposed: true
},
site: {
text: 'Website',
exposed: true
},
phone: {
text: 'Phone Number',
exposed: false
}
};
Template
<div class='table-header-row'>
<div class='first-header-cell' ng-repeat='obj in firstCellsHeaders'>
{{obj.text}}
</div>
<div class='middle-header-cell' ng-repeat-start='prov in providers' ng-if='providerColumns.price.exposed'>
{{prov}} {{providerColumns.price.text}}
</div>
<div class='middle-header-cell' ng-if='providerColumns.site.exposed'>
{{prov}} {{providerColumns.site.text}}
</div>
<div class='middle-header-cell' ng-repeat-end ng-if='providerColumns.phone.exposed'>
{{prov}} {{providerColumns.phone.text}}
</div>
<div class='last-header-cell' ng-repeat='obj in lastCellsHeaders'>
{{obj.text}}
</div>
</div>
<div class='table-row'>
<div class='first-cells' ng-repeat='obj in firstCells'>
{{obj.text}}
</div>
<div class='middle-cells' ng-repeat-start='prov in providers' ng-if='providerColumns.price.exposed'>
{{data[prov].price}}
</div>
<div class='middle-cells' ng-if='providerColumns.site.exposed'>
{{data[prov].site}}
</div>
<div class='middle-cells' ng-repeat-end ng-if='providerColumns.phone.exposed'>
{{data[prov].phone}}
</div>
<div class='last-cells' ng-repeat='obj in lastCells'>
{{obj.texLine2}}
</div>
</div>
It's essentially a table built out of div's in order to facilitate reordering the columns after angular finishes rendering.
Now I've realized the object represented in ng-repeat-start is more dynamic than I previously thought, and I want to be able to have a squared ng-repeat, i.e. nested repeat without nested elements, much like the oft-applied solution of using ng-repeat on a tbody element, and then an additional ng-repeat on the tr elements within it, which essentially is a flattened nesting effect. I need a solution for horizontal elements, preferably divs. I can't have them tied together in any way, however, so no nesting of divs or anything like that. Ideally it would look something like this:
<div ng-repeat='prov in providers' ng-repeat='col in providerColumns' ng-if='col.exposed'>
{{data[prov][col]}}
</div>
Any ideas?
Instead going with:
<div ng-repeat='obj1 in parent' ng-repeat='obj2 in obj1'>
{{content[obj1][obj2]}}
</div>
Why not use a nested ngRepeat, like this:
<div ng-repeat='obj1 in parent'>
<div ng-repeat='obj2 in obj1'>
{{content[obj1][obj2]}}
</div>
</div>