I use AngularJS. How to print to view 1 object multilevel when I haven't defined the inside attributes.
For example, I have object error:
{
"email": {
"Required": []
},
"first_name": {
"Min": [
"2"
]
},
"last_name": {
"Required": []
}
}
I want to print all the data in this object formed list
email: Required
first_name:Min 2
last_name: Required
...
Please imagine that this is just one part in many errors that may happens when submitting form.
The DOT notation of reading objects or properties nested deep within an existing object works with AngularJS too.
Let us say you have the following object:
$scope.newObject = {
email: {
required: true
},
firstName: {
min: 2
}.
lastName: {
required: true
}
};
If you wish to then access the required property of the nested email object, then you can access it like so:
<input type="text" ng-required="newObject.email.required">
Thus using the DOT notation, we can access the nested objects and their properties too.
<ul>
<li ng-repeat="obj in newObject">
<span >{{obj.email.required}}</span>
<span >{{obj.email.firstname.min}}</span>
<span >{{obj.email.lastname.required}}</span>
</li>
</ul>
I hope this may help you
Related
I've got one that I'm not getting too much traction on, Ive got everything working correctly except one element. Essentially I want to filter a return of "ev3_4" in the code. I'm not sure of the correct function. I'm pulling from an external source to get the data. and the info is inside a nested array of the array that I have been able to correctly return.
<template>
<!-- the array for the ev data -->
<div id="ev-deck" class="content">
<div id="text-box-ev" class="field">
<div class="control">
<!-- To change the number of events shown change the value for X in v-for="item in infodata.slice(0, X), this is the limiter for how many will loop before it stops -->
<div class="card-content has-background-dark has-text-light" id="ev-card" v-for="item in p3data.slice(0, 2)" :key="item.infodata">
<!-- Every row is a separate line in the event element and its position is manipulated by the column css -->
<div class="row">
<div id="ev-title" class="column"> <b>ev1:</b> {{ item.ev1 (firstname) }}</div>
<div id="ev-title" class="column"><b>ev2:</b> {{ item.ev2 (lastname)}}</div>
<div id="ev-title" class="column"><b>ev3:</b> {{ item.ev3_4 (city)}}</div>
</div>
<div class="row">
<div id="ev-title" class="column"><b>ev4:</b> {{ item.ev4 }}</div>
<div id="ev-title" class="column"><b>ev5:</b> {{ item.ev5 }}</div>
</div>
<div class="row">
<div id="ev-title" class="column-centered"><b>ev6:</b> {{ item.ev6 }}</div>
</div>
<div class="row">
<div id="ev-title" class="column-centered"><b>ev7:</b> {{ item.ev7 }}</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'ev',
}
data() {
return {
infodata: [],
},
// I know this is wrong and need help making this logic correct
item.ev3.filter(data => {
return data.ev3 === item.ev3_4
})
},
created() {
var info = 'some url'
axios.get(info)
.then( response => {
this.infodata = response.data;
console.log(response.data);
})
},
</script>
Here is an example of the the array its pulling
(infodata Array)
0:
ev1 (first name): joe
ev2 (lastname): blow
ev3 (address):
0:
ev3_1 (street number): 1234
ev3_2 (street name): main
ev3_3 (zip code): 12345
ev3_4 (city): tempe
Thanks for updating your question. Glad to hear you found a solution to access the data you needed.
Based on your edit, I think there are still some things worth noting. The data you are referring to is actually stored in an object rather than an array (though it does contain an array).
An array has the structure:
data = ["val1", "val2", "val3"]
And the data is accessed by index.
data[0] -> "val1"
data[1] -> "val2"
data[data.length - 1] -> "val3"
ev3[0]
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
Objects, on the other hand, contain properties consisting of key-value pairs. And have the following structure:
data: {
val1: "first",
val2: "second",
val3: {
a: "third a",
b: "third b",
c: "third c"
}
}
Object values are accessed using the key.
data.val1 -> "first"
data.val3.b -> "third b"
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object
Given the solution that worked for you,
item.ev3[0].ev3_4
Your data is stored as an object (item) with a property (ev3) that contains an array whose first index ([0]) is an object that has a property (ev3_4).
Your edit to your question definitely helps to clarify the structure of your data.
0:
ev1 (first name): joe
ev2 (lastname): blow
ev3 (address):
0:
ev3_1 (street number): 1234
ev3_2 (street name): main
ev3_3 (zip code): 12345
ev3_4 (city): tempe
But there are still some adjustments that you could make that would greatly improve your ability to work with and follow your data. And might help further clarify the concepts.
First, I would highly recommend using clear names for your object keys. What you have included in brackets is perfect, just use camel case to eliminate spaces.
This will make things much easier for you when writing code to accesses data (item.address.city as opposed to using names like ev3 and ev3_4), and will also help make your code more readable for others trying to follow your code.
Second, you are storing your address data (ev3[0]) as an object, inside of an array (hence the [0]).
From what you have shown, you are only using the first index of the array ([0]).
If this is the case you can just store the address object directly inside ev3, which will eliminate the need for you to specify [0] when you access the data.
person: {
firstName: "Joe",
lastName: "Blow",
address: {
streetNumber: "1234"
streetName: "Main Street",
zipCode: "90210",
city: "Fakesville"
},
phone: "1(222)333-4444"
}
Now you are able to access the same data you were looking to with the following:
person.address.city
And if you have additional people to store, that could/should be done inside an array, where they can then be accessed by their index or in a loop.
people = [
{
firstName: "Joe",
lastName: "Blow",
address: {
streetNumber: "1234"
streetName: "Main Street",
zipCode: "90210",
city: "Fakesville"
},
phone: "1(222)333-4444"
},{
firstName: "Rick",
lastName: "Sanchez",
address: {
streetNumber: "132"
streetName: "Cool Avenue",
zipCode: "98101",
city: "Seattle"
},
phone: "1(222)333-4444"
}
]
people[1].address.city -> "Seattle"
people[0].firstName -> "Joe"
How to apply a CSS active class to one item of three lists?
I get a list of objects from server. These objects has a property of type list. Here is a similar object.
[
{
name: 'europe',
countries: ["Englad", "France", "Germany", "Italy"]
}, {
name: 'asia',
countries: ["Japan", "China", "Iran", "Korea"]
}, {
name: 'Africa',
countries: ["Somalia", "Egypt", "Ghana"]
},
];
By default, the first item of the lists is selected. When the user clicks an another item, it should be selected without affecting the items of other lists.
Some information that might help.
The object is above is just an example. In future, I may get a list of more than three objects.
There is only one controller.
Each one of the countries has an 'id', but I have not included.
Here is an exmpale of this object on jsfiddle JSFiddle
Thank you so much.
Basically you would create an object to hold the selection, as you mentionned your data is variable the selection object generation should be dynamic. To do so I've taken advantage of the ECMAScript 2015 objects computed property names, there is more info on MDN for Object Initializer.
Having a default selection requires initialization as well.
Based on your fiddle, here's the html
<div ng-app ng-controller="ContinentController">
<ul>
<li ng-repeat="continent in continents">
<h2>{{continent.name}}</h2>
<ul>
<li ng-repeat="country in continent.countries">
<span ng-class="{active: selected[continent.name] === $index}"
ng-click="select(continent.name, $index)">{{country}}</span>
</li>
</ul>
</li>
</ul>
</div>
And the controller
function ContinentController($scope) {
$scope.continents = [{
name: 'europe',
countries: ["Englad", "France", "Germany", "Italy"]
}, {
name: 'asia',
countries: ["Japan", "China", "Iran", "Korea"]
}, {
name: 'Africa',
countries: ["Somalia", "Egypt", "Ghana"]
}, ];
$scope.selected = {};
$scope.select = select;
initializeSelection();
function initializeSelection() {
for (var i = 0; i < $scope.continents.length; i++) {
$scope.selected[$scope.continents[i].name] = 0;
}
}
function select(name, index) {
$scope.selected[name] = index;
}
}
Here's the working fiddle.
Now this assumes all you names are unique. Since you mentionned you have ids, if they are unique then using them as key instead of the name property would definitely be better.
So I create a cached json object within an array with the following method in Angular:
$scope.saveClaim = function() {
//always set isOffset to false - empty string does not work for non-string objects in web api when field is required
$scope.claimInfo.isOffset = false;
$scope.claimsSubmit.push($scope.claimInfo);
//clears scope so form is empty
$scope.claimInfo = {
id: "",
benefitId: "",
isSecIns: "",
isNoResId: "",
expenseTypeId: "",
fromDate: "",
toDate: "",
provider: "",
who: "",
depId: "",
age: "",
amount: "",
comments: "",
isOffset: ""
};
}
The idea is the user fills out a form, and at the end either selects to add another claim or submit a claim (the object). After each time the form is filled and user selects file or add another, the form clears and the user then enters more data. The results is an array of object(s) that look like:
[
{
"id": "",
"benefitId": "",
"isSecIns": "",
"isNoResId": "",
"expenseTypeId": "",
"fromDate": "",
"toDate": "",
"provider": "",
"who": "",
"depId": "",
"age": "",
"amount": "",
"comments": "",
"isOffset": false
}
]
If more than one claim is entered, then we get multiple objects with same properties.
Each claim is then displayed with limited data in info boxes that display only 3-4 of the properties.
So I am trying to figure best way to do 3 things. First, add a unique "id" to each object. Second, if the delete icon in the info box selected, then remove that object from the array and if the "edit" icon is selected in the info box, then all the relative properties that that object in the array is populated back to the form.
Googling best tries for this, but not sure how I can work with the json objects this for for now. Can some of you help me on this?
Thanks much.
Hard to give the best way. Probably comes down to your style and preferences. But here is one way to do it, to get you going.
Define your model. It will contain the claim that is bound to the form and an array of added claims.
$scope.viewModel = {
claim: {},
claims: []
};
Add a function that assigns a claim object with default values:
var resetClaim = function() {
$scope.viewModel.claim = {
name: '',
city: ''
};
};
resetClaim();
The form elements will use ng-model:
<input type="text" model="viewModel.claim.name">
We will use ng-repeat to show the added claims:
<tr ng-repeat="claim in viewModel.claims">
Our form will have two buttons:
<button type="submit" ng-click="saveClaim()">Save Claim</button>
<button type="button" ng-click="cancel()">Cancel</button>
The cancel button will just reset the form.
The saveClaim function will look like this:
$scope.saveClaim = function() {
if (!isValidClaim()) return;
$scope.viewModel.claim.id ? updateClaim() : saveNewClaim();
resetClaim();
};
The isValidClaim function just checks if we have entered the requied fields. You could use form validation for this instead.
In this solution when saving a claim it could either be a new claim or an existing one that we have edited, and what we will do in the two cases will differ, so we need a way to tell what we are doing. Here we just check if it has an id. If it hasn't - it's a new claim. If it has, it's an existing.
To save a new claim we will do the following:
var saveNewClaim = function() {
var newClaim = angular.copy($scope.viewModel.claim);
newClaim.id = id++;
$scope.viewModel.claims.push(newClaim);
};
Note that it's important that we use for example angular.copy to create a new copy of the claim that is bound to the view. Otherwise we would just push a reference to the same object to the claims array which is not good since we want to reset one of them.
In this example id is just a variable starting at 0 that we increment each time we create a new claim.
Each element in our ng-repeat will have an edit and a remove icon:
<tr ng-repeat="claim in viewModel.claims">
<th>{{claim.id}}</th>
<td>{{claim.name}}</td>
<td>{{claim.city}}</td>
<td><i class="glyphicon glyphicon-edit" ng-click="editClaim(claim)"></i></td>
<td><i class="glyphicon glyphicon-remove" ng-click="removeClaim(claim)"></i></td>
</tr>
The removeClaim function simply takes a claim and removes it from the array:
$scope.removeClaim = function(claim) {
var index = $scope.viewModel.claims.indexOf(claim);
$scope.viewModel.claims.splice(index, 1);
};
The editClaim function will make a copy of the claim to edit and put it in the variable that is bound to the form:
$scope.editClaim = function(claim) {
$scope.viewModel.claim = angular.copy(claim);
};
You can also do the following:
$scope.viewModel.claim = claim;
And when you edit the claim in the form it will update in the ng-repeat at the same time. But then you have no good way of canceling and the save button wouldn't be needed. So it depends on how you want it to work.
If you edit the claim in the form now and save, we will come back to the saveClaim function:
$scope.saveClaim = function() {
if (!isValidClaim()) return;
$scope.viewModel.claim.id ? updateClaim() : saveNewClaim();
resetClaim();
};
This time the claim will have an id, so the updateClaim function will execute:
var updateClaim = function() {
var claim = $scope.viewModel.claims.filter(function(c) {
return c.id === $scope.viewModel.claim.id;
})[0];
angular.extend(claim, $scope.viewModel.claim);
};
It will retrieve the claim that we are editing from the claims array based on the id. We need to do this since we used angular.copy earlier and have two difference objects.
We will then use angular.extend to move all the new edited values to the claim that we pressed edit on in the ng-repeat.
Demo: http://plnkr.co/edit/yuNcZo7nUyxVsOyPTBEd?p=preview
I created the following with the plugin: http://vitalets.github.io/checklist-model/
<section ng-repeat="owner in lord.owners">
<form ng-submit="foobar(owner)" name="update_location_form">
<input type="text" ng-model="owner.name">
<ul>
<li ng-repeat="sheep in sheeps">
<input checklist-model="owner.sheeps" checklist-value="sheep.id" type="checkbox">
<label class="checkbox">{{ sheep.name }}</label>
</li>
</ul>
<button type="submit">Submit</button>
</form>
</section>
All sheeps are shown in the list. And saving to my pivot table (manytomany-relation) also works.
But when I refresh the page, all checks are gone of course. How can I access them?
They're stored in:
{
id: 1,
name: "Obama",
farms: [
{
id: 10,
name: "VirtualFarm",
sheeps: [
{
id: 1,
name: "Foo",
},
{
id: 2,
name: "Bar",
},
{
id: 10,
name: "Cow",
},
{
id: 13,
name: "Hey",
},
]
}
]
}
But I really have now clue how I can check the checkboxes by default that are in the Pivot table.
Someone?
The checklist-model directive automatically checks the appropriate checkboxes based on the value of the checklist-model. You don't have to do anything else, your code looks fine. But ...
First of all, I suspect that owner in lord.owners must be something like owner in x.farms where x is the object that you pasted above.
And this is on the client side and even though you check this boxes, you still need to save them on the server-side. On a refresh, every data not persisted on the server side is lost.
I've got a 'user' object passed in when I load up a form, which I can use to directly populate my edit user form. So:
$scope.userData = getUserData();
<input id="uid" value="{{userData.uid}}"/>
<input id="name" value="{{userData.name}}"/>
My data looks like this:
userData = [{
"empId":1,
"name": "bob",
"roles":[{
"roleId":1,
"title":"boss"
},{
"roleId":2,
"title":"employee"
}]
}]
I've got a custom control that wants the roles as a FLAT array of titles.
So, this is what I'm hoping to produce:
<sys-multi id="roles" options="['boss','employee']"></sys-multi>
The trick here is that I'm hoping to do this IN THE TEMPLATE, so no functions so my controller. i.e. something like this (if it worked):
<sys-multi id="roles" options="{{userData.roles.name.join(',')}}"></sys-multi>
I've been playing with grep, but angular doesn't like grep within its {{}}'s.
How about adding a getter (or a function) to your userData object:
$scope.userData = {
"empId":1,
"name": "bob",
"roles":[{
"roleId":1,
"title":"boss"
},{
"roleId":2,
"title":"employee"
}],
get roleNames() {
return this.roles.map(function (role) {
return role.title;
});
}
};
...and then using it this way:
<sys-multi id="roles" options="userData.roleNames"></sys-multi>
http://codepen.io/jlowcs/pen/emPKrB