Vue template object key alternative reference without implicitly calling with key name - javascript

I have an object which is retrieved from an API and key names are unknown. Let's assume it will come in the following format:
var attributes = {
"Colour": ["red", "black", "purple"],
"Size": ["8.0", "8.5", "9.0", "9.5", "10.0"]}
How can I access this data directly in Vue without knowing keys? I know the following would work if I had known the keys, but I am looking for an option where I can refer to the arrays without knowing the key names, like normal Javascript values are accessed through key name (square brackets).
<table>
<tr>
<th v-for="(values, name) in attributes"> [[ name ]]</th>
</tr>
<td>
<select">
<option v-for="value in attributes.Colour"> [[ value ]] </option>
</select>
</td>
<td>
<select">
<option v-for="value in attributes.Size"> [[ value ]] </option>
</select>
</td>
</table>
I have tried this so far (e.g. attributes[name]), which does not seem to be correct Vue template syntax:
<table>
<tr>
<th v-for="(values, name) in attributes"> [[ name ]]</th>
</tr>
<td v-for="value in attributes[name]">
<select">
<option> [[ value ]] </option>
</select>
</td>
</table>

You need to do something like this.
Since your attributes is an object with dynamic keys, loop through the object to get the keys.
Then loop through each of the keys of the object attributes to get array list.
Also, the <td> tag should be wrapped inside a <tr> tag
function callMe(){
var vm = new Vue({
el : '#root',
data : {
attributes : {
"Colour": ["red", "black", "purple"],
"Size": ["8.0", "8.5", "9.0", "9.5", "10.0"]}
},
methods: {
}
})
}
callMe();
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.11/dist/vue.js"></script>
<div id='root'>
<table>
<tr>
<th v-for="(item, key, index) in attributes "> {{ key }} </th>
</tr>
<tr>
<td v-for="(item, key, index) in attributes">
<select>
<option v-for="name in item"> {{ name }} </option>
</select>
</td>
</tr>
</table>
</div>
</div>

You can use indexes. See: https://v2.vuejs.org/v2/guide/list.html#Mapping-an-Array-to-Elements-with-v-for.
<table>
<td>
<select v-for="(value, index) in attributes">
<option> {{ attributes[index] }} </option>
</select>
</td>
</table>
I'm also somehow lost in your code, because I'm not sure if you want to render more options, selectsor tds. In my example there will be rendered a number of options based on the attributes that you pass into select's v-for.

Related

How to display a dropdown based on contents of the current array index in a table

I have a object array that I want to use in a table. I need a drop down select if the validvalues has a value. How to you do this so that each row of the table has different options from the array? If the validvalues is empty, it should be a div/input in the table row but it validvalues is not empty, it should be a dropdown with the validvalues as the options of the select.
As written, updateOptions() doesn't get called and an empty select shows on every row (insert sad emoji).
TS file
tags = [
{tagName: 'AppID', value: 'T400', validvalues: 'T100/T200/T300/T400/T500'},
{tagName: 'Series', value: 'SUPR', validvalues: ''},
{tagName: 'Collection', value: 'AUTO', validvalues: 'EFIT/AUTO/FLEET'},
{tagName: 'Function', value: 'Accounting', validvalues: 'Sales/Marketing/Accounting/Shop'},
{tagName: 'Contact', value: 'Jim Jones', validvalues: ''}]
validValuesArray: any = [];
updateOptions(parsingString: string) {
let tagValidValuesArray = parsingString.split('/');
}
HTML file
<table>
<tr>
<th>Tag Name</th>
<th>Value</th>
</tr>
<tr *ngFor="let tag of tags; let i=index">
<td>
<div>{{tag.tagname}}</div>
</td>
<td>
<div *ngIf="!tag.validvalues">
<input type="text" name="value" [(ngModel)]="tag.value">
</div>
<div *ngIf="tag.validvalues">
<select [(ngModel)]="tag.value" (ngChange)="updateOptions(tag.validvalues)">
<option *ngFor="let value of validValuesArray">{{value}}</option>
</select>
</div>
</td>
</tr>
</table>
If I understand you correctly you want your first table row to have a dropdown with the options:
T100
T200
...
Then your would have to have away to convert your string of validValues into an interable type. For example by calling validValues.split('/') this would convert your string into a string[] which you could then loop over.
Since you typically don't want to call methods in your template for performance reasons I would recommend to transform the validValues into an Array when you load them, or even before that in your database if possible unless there is a specific reason, why you would hold "a list of Options" as anything but a "listlike" data structure.
The solution is/was to load the validValuesArray after tagDtail array is loaded and then use the validValuesArray for the dropdown options. Like this...
for (var m = 0; m < this.tagDtails[0].tags.length; m++){
let currentTag = this.tagDtails[0].tags[m];
let parsingString = currentTag.validValues;
this.validValuesArray.push(parsingString.split('/'));
}
This will create an array or arrays that looks like this:
validValuesArray = [
["T100","T200","T300","T400","T500"],
[],
["EFIT","AUTO","FLEET"],
["Sales","Marketing","Accounting","Shop"],
[]]
then, in the html, loop through the validValuesArray
<tr *ngFor="let tag of tagDtails.tags; let i = index">
<td>
<div>{{ tag.tagName }}</div>
</td>
<td class="td-fix">
<div *ngIf="this.validValuesArray[i]==''">
<input type="text" class="form-control" name="tagValue" [(ngModel)]="tag.tagValue">
</div>
<div *ngIf="this.validValuesArray[i]!=''">
<select [(ngModel)]="tag.value">
<option *ngFor="let value of validValuesArray[i]">{{value}}</option>
</select>
</div>
</td>
</tr>

How to bind an object to HTML table in Vue.js, where its properties are dynamically created?

I am using vue.js library for front-end development.
I came a cross a scenario where my JavaScript method returns a list, which has objects, object's number of properties can change each time after method execution.
example my list can contain these type of objects in 2 different executions.
var obj = {
Name : "John",
2020-Jan: 1,
2020-Jul: 2
}var obj = {
Name: "John",
2020-Jan: 1,
2020-Jul: 2,
2021-Jan: 3,
2021-Jul: 4
}
Since Property name is dynamically changes is there any way to bind to HTML ?
<div >
<table>
<thead>
<tr>
<th v-for ="row in Result.Headers">
{{row}}
</th>
</tr>
</thead>
<tbody>
<tr v-for="item in Result.Data ">
<td>
{{item.2020-Jan}} // Because don't know the number of properties until run time
</td> // No of <td/>'s can change on no of properties.
<td> // exactly don't know how many <td>'s needed there.
{{item.2020-Jul}}
</td> <td>
{{item.2021-Jan}}
</td>
</tr>
</tbody>
</table>
</div>
Is there way to bind these type of object to fronted in vue.js ?
You need to loop over the item's keys again. This will show all the values in the object
<tbody>
<tr v-for="item in Result.Data ">
<td v-for="(value, key, index) in item">
{{value}}
</td>
</tr>
</tbody>
If you want to filter some of them, for instance check that the keys are valid dates you need to add a v-if and use Date.parse to check for this.
<tbody>
<tr v-for="item in Result.Data ">
<td v-for="(value, key, index) in item" v-if="Date.parse(key) !== NaN">
{{value}}
</td>
</tr>
</tbody>
if u wana show all attr-> u can use this:
<ul v-for="item in Result ">
<li v-for="(value,key,index) in item">{{value}}</li>
</ul>
if u wana show all days u can use v-if and compute to complete youself fillter
<div id="app">
<ul v-for="item in Result" >
<li v-for="(value,key,index) in item" v-if="canShow(key)"> index:{{index}}------ key: {{key}} ------ value:{{value}} </li>
</ul>
</div>
<script>
var vue=new Vue({
el:'#app',
data:{
Result:[{
name: 'SkyManss',
2020-Jan: 1,
2020-Jul: 2
},{
name: 'SkyManss2',
2020-Jan: 1,
2020-Jul: 2,
2021-Jan: 3,
2021-Jul: 4
}]
},
computed:{
canShow(){
return function(skey){
return skey.indexOf('-') > -1;
}
}
}
});
</script>
after some research and some of your suggestions I came up with an answer.
<div>
<table>
<thead>
<tr>
<th v-for ="row in Result.Headers">
{{row}}
</th>
</tr>
</thead>
<tbody>
<tr v-for="item in Result.Data ">
<td v-for="row in Result.Headers">
{{item[row]}}
</td>
</tr>
</tbody>
</table>
</div>
Javascript code
this.Result.Headers = Object.keys(result.data[0]);
this.Result.Data = result.data;
But this code only worked for the first time. second time data didn't get updated. So I updated JavaScript code to following code.
Vue.set(self.Result, 'Headers', []);
Vue.set(self.Result, 'Result', []);
this.Result.Headers = Object.keys(result.data[0]);
this.Result.Data = result.data;
Vue does not allow dynamically adding new root-level reactive properties to an already created instance. That I got to know from following post.
vue.js is not updating the DOM after updating the array
Thank You All !!!

Dynamic attribute selection in Vue - previous selection is being made blank

The attributes data comes from an API and the attribute names are dynamic, however to make this example simpler i have put an example with an object which has Colour and Size. I was primarily trying to map data to an object selectedAttrObj - which has no problems, however when the second sets of attributes are selected (Size), the first one (Colour) is becoming blank. This must be due to the fact that the first v-model="selected" is being overwritten when second set is selected. This is a visual experience, and how I can make sure the first select stays with the selected option. Please do not try to hardcode as there could be countless number of attributes, so it needs to be dynamic (hence the reason for using selected for all attributes). If there is a better and simpler way of mapping the selected data to selectedAttrObj to avoid blanking out previous selections, please fire away! Thanks
function callMe(){
var vm = new Vue({
el : '#root',
data : {
attributes : {
"Colour": ["red", "black", "purple"],
"Size": ["8.0", "8.5", "9.0", "9.5", "10.0"]},
selectedAttrObj: {},
selected: ""
},
methods: {
selected_attributes(name, value) {
this.selectedAttrObj[name] = value
console.log(this.selectedAttrObj)
}
}
})
}
callMe();
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.11/dist/vue.js"></script>
<div id='root'>
<table>
<tr>
<th v-for="(item, key, index) in attributes "> {{ key }} </th>
</tr>
<tr>
<td v-for="(items, key, index) in attributes">
<select v-model="selected" #change="selected_attributes(key, selected)">
<option v-for="name in items"> {{ name }} </option>
</select>
</td>
</tr>
</table>
</div>
</div>
You can change your data variable selected to be a object and save the values based you the given key you are iterating.
Here is a snippet:
function callMe(){
var vm = new Vue({
el : '#root',
data : {
attributes : {
"Colour": ["red", "black", "purple"],
"Size": ["8.0", "8.5", "9.0", "9.5", "10.0"]},
selected: {}
}
})
}
callMe();
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id='root'>
<table>
<tr>
<th v-for="(item, key, index) in attributes "> {{ key }} </th>
</tr>
<tr>
<td v-for="(items, key, index) in attributes">
<select v-model="selected[key]">
<option v-for="name in items"> {{ name }} </option>
</select>
</td>
</tr>
</table>
</div>
</div>

ng-repeat issue with JSON Object

So I'm trying to print the keys and values of a simple JSON object inside an HTML table with ng-repeat but not able to print it on the html page. The JSON object has been received from the backend and am trying to populate that in the frontend. I understand that I am doing a silly mistake somewhere but can't understand where.
JSON Object
json_data ={
user1 : "matt",
user2 : "kim",
user3 : "Tim"
}
$scope.rows = json_data;
HTML code..
<table ng-if="displayTable">
<caption>Results</caption>
<tr>
<th>Username</th>
<th>Name</th>
</tr>
<tr ng-repeat="(key, value) in rows">
<td> {{key}} </td> <td> {{ value }} </td>
</tr>
</tr>
</table>
Can't understand what silly mistake I am doing here.
Try {{rows.key}} and {{rows.value}}. Although I don't thing this is the answer. Give it a try..
Alternative ly you can try to see if it works with just one , either key or value...
First at all, the (key, value) is more well represented by (index, value).
A correct version of this piece of code will output this:
0 {"user1":"matt","user2":"kim","user3":"Tim"}
which 0 is the first index of an array and the json is the entire value.
So, i guess you are using a bad approach.
Try to modify your array to something like that:
$scope.rows = [
{key: 'user1', user: 'matt'},
{key: 'user1', user: 'kim'},
{key: 'user1', user: 'Tim'},
];
And modify your HTML to:
<table ng-if="displayTable">
<caption>Results</caption>
<tr>
<th>Username</th>
<th>Name</th>
</tr>
<tr ng-repeat="row in rows">
<td> {{row.key}} </td> <td> {{ row.user }} </td>
</tr>
</tr>
</table>

nested ng-repeat that one depend on the other

I have an issue with angular, I want to use two nested ng-repeat in a data table where the first get the data, and the second get the name of field to be retrieved from the data (retrieved in the first ng-repeat)
here is what I tried to do with code :
<table md-table flex-order-gt-sm >
<thead md-head>
<tr md-row >
//1st : get the name of fields, not a problem
<th md-column ng-repeat="field in fields">{{item.name}}</th>
</tr>
</thead>
<tbody md-body>
<tr md-row ng-repeat="item in items">
<td md-cell ng-repeat="field in fields" >
//here is the problem I want to get the item that it's field name is field
{{item.{{field}} }}</td>
</tr>
</tbody>
</table>
for example if fields contain :{'a','b','c'}
and items contains {'a':'1','b':'2','c':'3'};
I want for example for the 1st iteration of {{item.{{field}} }} to return 1
Use toString() to retrieve the scope data in an scope object.
<tr md-row ng-repeat="item in items">
<td md-cell ng-repeat="field in fields" >
{{item[field.toString()]}}
</td>
</tr>
Here is the plunker
As an alternative you could also use a filter:
<td md-cell ng-repeat="field in fields | filter: { name: 'field' }">
</td>
You need to get fields collection according to item of items collection after
getFieldsByItem(item)
Then you can get field from fields collection
{{field}}

Categories