I have a Vue component that is passed JSON data as a prop. The schema changes depending on the type of the object—the component is generic—and some of the JSON has nested objects/arrays.
The data:
"check": {
"id": "d5d1d763236f3",
"created_on": "2016-08-05T15:49:18.263399Z",
"type": "A",
"header": {
"Host": ["appname.com"]
},
"method": "GET"
}
The template
<div class="results" v-if="type">
<table v-for="item in type">
<tbody>
<tr v-for="(key, val) in item">
<td>{{ key }}</td>
<td><input v-model="val" type="text"/></td>
</tr>
</tbody>
</table>
</div>
Is there a sensible way to dynamically check whether val is of an Object or Array, and if so, recurse over it? It's important to also retain the binding so that the state is updated when those nested fields change (so we can HTTP PATCH any edits).
e.g. function iterate(obj) that can render the nested object. JS is not my strong suite, and isEnumerable or hasOwnProperty('length') seem to be fragile.
Related
I'm working in a project to help a friend, so most of the code in the services and the backend was already there, so I've been struggling with the structure and sometimes I get lost.
Here's my problem
This is the structure of the data on the API:
{
"title": "",
"iconURL": ",
"linkedRightsIDs": [
""
],
"linkedRights": [
{
"id": ,
"creationDate": "",
"sections": [
"women"
],
"defLanguage": "en",
"countryApplied": "united states",
"statesApplied": [
"all"
],
"title": "",
"translations": [
"en"
],
"disable": false,
"content": null
}
]
}
What I'm trying to achieve, is to make a table inside my component using the LinkedRights data. Right now, this structure only have 1 linkedRight (I deleted the data inside for privacy)
Anyways, here's the method regarding the service and model in my component.ts:
onModelLoadedAsync() {
super.onModelLoadedAsync();
if (this.mode == 'create') {
this.model = LocalityInfo;
} else {
if (this.model.iconURL){
this.imageSrc = this.model.iconURL;
}
}
if(this.mode == 'edit'){
const data= Object.entries(this.model.linkedRights); //this is me just testing
console.log(data);
}
}
here's the html of the table I'm trying to display, this is and edit route so there's a query param for the id in this view
<div class="table-responsive">
<table class="table table-hover">
<thead class="thead-dark">
<tr>
<th>Title</th>
<th>Sections</th>
<th>States</th>
<th>Enabled</th>
<th>Creation Date</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of data">
<td>{{item.title}}</td>
<td>{{item.sections}}</td>
<td>{{item.statesApplied}}</td>
<td>{{!item.disabled}}</td>
<td>{{item.creationDate}}</td>
</tr>
</tbody>
</table>
</div>
</div>
What I was trying to do, was to convert the JSON into an array so I could display it since there's an error that shows on the console that said this:
core.js:6456 ERROR Error: Cannot find a differ supporting object '[object Object]' of type'object'. NgFor only supports binding to Iterables such as Arrays.
I have a collection named "pIds" in mongoDB and with multiple arrays:
{
"_id" : "Coms>f41a3480af751a7a",
"pIds" : [
"pid_833d82c2f32b7dc0",
"pid_833d82c2f32b7dc0",
"pid_833d82c2f32b7dc0",
],
"dudes" : [
"AB",
"AC",
"BC"
],
"ho" : [
"Coms>f41a3480af751a7a",
"Coms>f41a3480af751a7a",
"Coms>f41a3480af751a7a"
],
"ps" : [
"vf",
"ou",
"rwf"
],
}
Now I want to render these elements dynamic into a HTML table so that the table changes the same way the data in the collection changes. So the table should automatically add new elements, when new elements are written into the collection "pIds". I thought about using {{each}}.
JS-Helper:
Template.home.helpers({
'pIdsRendering': function() {
if (Meteor.userId()) {
var pId = pIds.find({'_id': Session.get('pIdshome')}).fetch();
return pId;
}
},
});
HTML:
<tbody>
{{#each pIdsRendering}}
{{#each pIds}}
<tr><td>{{this}}</td></tr>
{{/each}}
{{/each}}
{{#each pIdsRendering}}
{{#each dudes}}
<tr><td>{{this}}</td></tr>
{{/each}}
{{/each}}
[...and so on...]
</tbody>
Actually this works and new elements are added to the table, but I just can´t put the content into the right cells of the table. It puts the content all in one column like the data of the table would be written like this:
So, I think it is about "logical order", but I just can not get it done...In the end the table should look like this:
You create for every array item new <tr> tag and this is the reason why every item is in a new row. I suggest you to change your collection schema a little bit. I would do it like below:
{
"_id" : "Coms>f41a3480af751a7a",
"data": [
{
"pid": "pid_833d82c2f32b7dc0",
"dude": "AB",
"ho": "Coms>f41a3480af751a7a",
"ps": "vf"
},
{
"pid": "pid_833d82c2f32b7dc0",
"dude": "AC",
"ho": "Coms>f41a3480af751a7a",
"ps": "ou"
}
]
}
Then in your Blaze template you can show records much easier
{{ #each record }}
{{ #each data }}
<tr>
<td>{{ pid }}</td>
<td>{{ dude }}</td>
<td>{{ ho }}</td>
<td>{{ ps }}</td>
</tr>
{{ /each }}
{{ /each }}
Your actual schema can lead to unexpected errors. For example when pIds array will have more elements than dudes. It is more difficult to validate it. By using an object you can do it much more easily. Also, I guess that you want to bind pIds[index] element with dudes[index] element. In this case using arrays like you did isn't a correct way.
Below is my JSON object which I would like to display the name in both the parent and child array.
$scope.result= [
{
"id": 1,
"name": "1002",
"parentArray": [
{
"id": 28,
"name": "PRODP1",
"shortCode": "PRODP1"
}
]
}
I want to display Name:1002 Parent_Name:PRODP1
I tried {{item.name}} which will only display 1002.But I need to display the name of parentArray as well.
Since the parentArray is also an array your going to need a nested ng-repeat.
If this is a large page then this may cause a performance issue.
<div ng-repeat="item in result">
{{item.name}}
<div ng-repeat="innerItem in item.parentArray">
{{innerItem.name}}
</div>
</div>
parentArray is an...array, so you need to access it using an index:
<div ng-repeat="item in result">
Name: {{ item.name }} Parent_Name: {{ item.parentArray.length ? item.parentArray[0].name : '' }}
</div>
That's under the assumption that there is one object in parentArray. You might need to iterate it, or you might need to check to see if it exists depending on your requirements.
I'm getting some JSON returned from a server for which I'd like to iterate over the key value pair label and value. I tried to access the values by using the following but I get nothing.
What am I missing for this to work?
HTML :
<tr ng-repeat="(label, value) in data[0].[label]">
<td>{{label}}</td>
<td>{{value}}</td>
</tr>
JSON input :
"data": {
"title": {
"label": "Title",
"value": "Mr"
},
}
<tr ng-repeat="title in data">
<td>{{title.label}}</td>
<td>{{title.value}}</td>
</tr>
(Assuming your Json is in a variable like $scope.data)
I have some data that I want to output using jsViews. The case is that objects in data array can have different set of attributes/columns based on some conditions. I store those attributes names in settings and would like to be able to print contents of data with all additional columns stored in a settings array. For example:
data = {
view_settings: [{
property_name: "prop1"
},
{
property_name: "prop2"
}
],
object_list: [{
id: "180",
name: "test1",
prop1: "test-prop-1",
prop2: "test-prop-2"
}
]
}
What I would like to achieve is to display contents of object_list using property listing from view_settings. Is this even possible using jsViews?
The best way to find an answer for you question is to ask it first, understand it (rubber duck method) and then find an answer.
In order to do this we need to alias objects twice. Here is my simplified jsViews template code which will display correctly data from example from my question:
<script id="template1" type="text/x-jsrender">
<table>
<thead>
<tr>
<th>Name</th>
{{for view_settings}}
<th>{{>property_name}}</th>
{{/for}}
<th></th>
</tr>
</thead>
<tbody>
{{for object_list ~view_settings=#data.view_settings}}
<tr>
<th>{{>name}}</th>
{{for ~view_settings ~object=#data}}
<th>{{:~object[property_name]}}</th>
{{/for}}
<th></th>
</tr>
{{/for}}
</tbody>
</table>
</script>
Hope this spares someones time ;)