Access loop index in the current elements data attribute - VueJS - javascript

I wanted to access the current index of a loop inside another attribute of the same element that has the v-for directive.
The HTML content is :
<div id="app">
<div v-for="count in length" data-my-attribute="here" class="target">{{count}}</div>
</div>
And the JS code:
var app = new Vue({
el : '#app',
data: {
length: 9,
}
});
I know I can access the current loop index 'inside' the div with the class target.
The way it does with the {{ count }}
But is it possible to access the count inside the value of the attribute data-my-attribute ?
(I mean in the place of the word "here")

You could access that variable using the binding as follow :
<div id="app">
<div v-for="count in length" :data-my-attribute="count" class="target">{{count}} </div>
</div>
like the case when you want to define a dynamic ids
<div id="app">
<div v-for="count in length" :id="'divNum'+count" class="target">{{count}} </div>
</div>

Related

Can I get the position of the div element (created by a loop from JavaScript) on a button click inside of that div?

I want to send a value from html to javascript using javascript variable.
I've created a div from javascript like this:
<body>
<div id="row" class="category-cards">
// creates from js
</div>
</body>
<script>
var d1 = document.getElementById("row");
for (let i=5; i>0; i--) {
d1.insertAdjacentHTML('beforeend',
<div class="card card-small card-category">
<div class="card-del-btn">
<button id="btnDel" onclick="deleteCategory(i)"> <b> × </b> </button>
</div>
<!-- displays the record --!>
</div>
}
function deleteCategory(index){
// takes the index and searches the mysql database for match, and deletes the record
}
</script>
Each iteration of the for loop inserts a card of a record from the database, and I wish to delete that record from the document, as well as the database, when the button is clicked.
Is there a way to associate a unique id or value to each card and send it through the onclick?
I have tried sending the value of i but it is always the last index, which in this case was 0.
There many ways to achieve what you looking for but simplest one would be to use custom html attributes and provide element that triggered event as argument to your callback.
This could be achieved like this
function handleClick(element) {
const elementData = element.getAttribute('data-my-data')
// do some stuff here with element data
}
Using your code:
d1.insertAdjacentHTML('beforeend', `
<div class="card card-small card-category">
<div class="card-del-btn">
<button data-my-data="here goes your data" onclick="handleClick(element)"> <b> × </b> </button>
</div>
</div>
`)

Print, on paper, element in a for-loop

Here's what I'm trying to accomplish:
<div v-for="columns in pageStructure"
//Print from here
<div v-for="htmlIWantPrinted in array">
...some content...
<button #click="printElementDiv()">Print</button>
</div>
//To here
</div>
I'm trying to print the specific content created in the for-loop. Button included.
Since there are multiple columns, I can't just put an id on it and I can't use ref either for the same reason, and using the element as a parameter for the method grabs the object instead of the html.
Simply add the value you passed to v-for loop and see the magic. This might not actually be what you want, but it should give a better understanding of what you're going to do. This is just enough.
var app = new Vue({
el: '#app',
data: {
pageStructure: ['Welcome', 'to', 'vue', 'world']
},
methods: {
printElementDiv(el) {
console.log(el)
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="column in pageStructure">
<h1>Div: {{column}}</h1>
<button #click="printElementDiv(column)">Print</button>
</div>
</div>
I ended up using #RohìtJíndal' answer from the comments:
<div v-for="columns in pageStructure"
//Print from here
<div v-for="htmlIWantPrinted in array" :id="htmlIWantPrinted.id">
...some content...
<button #click="printElementDiv()">Print</button>
</div>
//To here
</div>
If you don't have a variable available, you can make one and increment it as part of the loop.

Losing scope when using ng-include for recursion ( Updating object at run time, not reflecting the changes on child template) in angularjs

I'm using ng-include for recursion. it's loading correct at first time but when I change anything in the object at run time, it doesn't reflect the changes on html. ng-include will create a child scope for that, so its not getting changes from parent scope. How can I bind the scope or reflect the changes in the html? Below is the code snippet for main.html
<div ng-switch on="value.length>0">
<div ng-switch-when="true">
<div ng-init="item = value[0];" ng-include="'test/views/partialTemp.html'">
</div>
</div>
</div>
In Partial Template
<div class="row" ng-repeat="(key, result) in item" ng-if="item ">
.......
<div ng-switch on="result.length > 0 ">
<div ng-repeat="tempValue in result">
<div ng-switch-when="true">
<div ng-init="item = tempValue;" ng-include="'test/views/partialTemp.html'"></div>
</div>
</div>
</div>
....
</div>
In JS File
onRadioButtonChange = function(key, value, item) {
var self = this;
self.serviceObj.Response.values = self.updateServiceObject(self.serviceObj.Response.values, key, value, false); // Updating the actual object which came from service
self.objectToShow = JSON.parse(JSON.stringify(self.serviceObj)); // Taking the actual object which will show in the HTML
self.objectToShow.Response.values = self.filterObjectToShow(self.objectToShow.Response.values); // it'll add/remove the child radio button
}
objectToShow is the object which I'm using to render the html

Data bind over in array in knockoutjs

I have an array as follows:
self.arrayObj : Array[2]
>0:Object
>Display1
->InnerObjects
>__proto
>1:Object
>Display2
-->InnerObjects
My interntion is to display "Display1" and "Display2" which are strings
I am doing the html binding as follows:
<div data-bind="foreach: self.arrayObj">
<span data-bind="text:$data[0]"></span>
</div>
How can I iterate over the array and display only texts?
In case your array is just an array of strings you should do the following:
<div data-bind="foreach: self.arrayObj">
<span data-bind="text:$data"></span>
</div>
In case your array is an array of objects which have for example a property 'Name', which is a string, then you do it like this. Knockout knows you're inside the foreach so it knows which element you're at while looping.
<div data-bind="foreach: self.arrayObj">
<span data-bind="text:Name"></span>
</div>
I would like to answer my own question.
It is not a simple thing when we want to bind the object with dynamic keys and values in the UI using Knockout js. If we have the fixed keynames then its easy.
What I did was , converted the json object to 2-D array :
In the .js file
var 2Darray = jsonObject.map(function(val) {
var keyname = Object.keys(val)[0];
var value = val[keyname];
return [keyname,value];
});
In the html file , we can bind it two times in a loop:
<div data-bind:"foreach:2Darray">
<div data-bind:"foreach: $data">
<div data-bind:"text:$data[0]">
<div data-bind:"foreach: $data[1]">
<div data-bind:"text:$data.val">
</div>
</div>
</div>

How can I dynamically render both javascript data and html within the same angular curly braces ({{ }})?

I am rendering different kinds of attributes within the same html element in the following manner:
Javascript:
var dataAttribute = {
value:function(){ return 1;}
}
var listAttribute = {
value:function(){ return "<div>My Arbitrary HTML
<div>1</div>
<div>2</div>
<div>3</div>
</div>";}
}
var attributes = [dataAttribute,listAttribute]
HTML:
<div ng-repeat="attribute in attributes"> {{ attribute.value() }} </div>
How do I get the html in the listAttribute to render as HTML and not as text, while still retaining the ability to render the normal data of the dataAttribute?
You just should not. Use ng-switch directive if you want to render different things based on properties of items in your collection. ( in worst case use series of ng-if inside your ng-repeat)
Do not invent another templating engine if you already using angular, you are just confusing yourself.
Little more explanation here. You already have code that generates that html somewhere. It really better by angular directives.
<div ng-repeat="attribute in attributes" ng-switch="attribute.type">
<div ng-switch-default> {{ attribute.value() }} </div>
<div ng-switch-when="table"><my-table data='attribute.value()'></my-table></div>
<div ng-switch-when="list"><my-list data='attribute.value()'></my-list></div>
</div>
And set of directives
.directive('myTable', myTable).directive('myList', myList)
will hold all the logic to produce html from the data.
I.E. don't mix layout and data in one structure.
The solution was a combination of #vittore and #YOU's answers:
Javascript:
var dataAttribute = {
value:function(){ return 1;},
type:'data'
}
var listAttribute = {
value:function(){ return "<list-directive></list-directive>";},
type:'list'
}
var attributes = [dataAttribute,listAttribute]
HTML:
<div ng-repeat="attribute in attributes" ng-switch="attribute.type">
<div ng-switch-default> {{ attribute.value() }} </div>
<div ng-switch-when="list" ng-bind-html="attribute.value()"></div>
</div>
Thanks!

Categories