I have some data that I would like to loop through with ngRepeat and access data dynamically that's either on the top level or nested under a couple of levels.
However, it seems like I can get the top level properties to show up, but not when its nested.
JS:
var mapping = [
{property:'a'}, // works
{property:'b.c1'}, // doesn't work
{property:'b.c2'} // doesnt work
];
var arr = {
a: 'text',
b: {
c1: 'text2',
c2: 'text3'
}
};
HTML:
<div ng-repeat="mappingItem in mapping">
<p>{{arr[mappingItem.property]}}</p>
</div>
You can use angular's $parse service to evaluate the expression against arr:
$scope.map = function(property) {
return $parse(property)(arr);
};
<div ng-repeat="mappingItem in mapping">
<p>{{map(mappingItem.property)}}</p>
</div>
http://plnkr.co/edit/tPYcyT4HhqaepJZl0kd8?p=preview
I doubt your approach will work. Reason being the way you are trying to access the object is incorrect, i.e.: arr[mappingItem.property] will become arr['b.c1'] but your object doesn't have a key 'b.c1'. #DivyaMV's suggestion won't work either because property b in the mapping isn't an object hence it doesn't have a key c1. I'd suggest you either change the structure of your object OR you change how you are trying to access your object i.e. use ng-if to check for multiple levels, OR instead of looping, display the properties one by one
If you use {"property":"b","chiled":"c1"} type of structure then it works.
var mapping = [
{property:'a'},
{"property":"b","chiled":"c1"},// works
{property:'b.c2'}
];
<div ng-repeat="mappingItem in mapping">
<p>{{arr[mappingItem.property][mappingItem.chiled]}}</p> <!-- it works for second object-->
</div>
Related
I'm trying to render a table using data from an array of objects. These have been created with a constructor which has a number of prototype methods. All the methods work correctly outside of the specific problem I'm having.
The table needs to be rendered dynamically, eventually with user input selecting which columns they want rendered and in which order. As such I'm trying to use a separate array to house the selected fields (filled in manually for now).
Below I have an example of the object, the prototype, the array, and the array of objects forEach method containing a simple console.log.
const jsonResultTotal = {
new_stats: [
{
revenue: 'US$200.00',
cost: 'US$4.09',
}]
};
jsonResultTotal.prototype = {
...jsonResultTotal.prototype,
roas: function() {
return (Number(this.revenue.replace(/[^0-9.]/g, '')) / Number(this.cost.replace(/[^0-9.]/g,''))).toFixed(
2);
},
const rowCellContent = [
'revenue',
'cost',
roas(),
'roas()'
roas
'roas'
];
jsonResultTotal.new_stats.forEach(function(e) {
for (i=0; i<=5;i++){
console.log(e[rowCellContent[i]])
}
}
The result of the above code is
'US$200.00'
'US$4.09'
undefined
Well, actually that specific rowCellContent array will result in roas() is not defined, but the point is that none of the methods will work.
If I console.log(e.roas()) then it works, so accessing the method seems to be fine. I've tried arrow functions in the rowCellContent array, as well as full functions with a return of this.roas(), I've tried to used bind on the e[rowCellContent[i]]
There doesn't seem to be any issues calling the properties through the array, or calling the prototype methods directly, I just can't get the methods via the array to work.
Any help would be appreciated.
I have a form that uses $scope.booking variable composed of several fields and array, all loaded from HTML.
I need to add an array of object from javascript, adding one object per time.
I tryed
$scope.booking.newExternalUsers[$scope.count]= $scope.user.newExternalUser;
and
$scope.booking.newExternalUsers.push=$scope.user.newExternalUser;
but I receive Cannot set property '0' of undefined and Cannot set property of undefined, it is correct because I have instantiated only $scope.booking={}
Maybe is a stupid question, but I am almost new in angularjs, how can I add the $scope.user.newExternalUser one pertime (for each button event)?.
Thanks
You should define the array first before set values to it.
like this:
$scope.booking = {};
$scope.booking.newExternalUsers = [];
or
$scope.booking = {
newExternalUsers: []
};
Then
You can add items to it as you want, like this:
$scope.booking.newExternalUsers[$scope.count]= $scope.user.newExternalUser;
or using Array.prototype.push()
$scope.booking.newExternalUsers.push($scope.user.newExternalUser);
First define the property newExternalUsers in booking array first
$scope.booking={
'newExternalUsers' : []
}
or
$scope.booking.newExternalUsers=[]
Then push the item to an booking array
$scope.booking.newExternalUsers.push($scope.user.newExternalUser);
You have to instantiate $scope.booking.newExternalUsers=[]
I'll assume you have a controller. In that controller you can have this:
$onInit() {
this.booking = { newExternaUsers: [] };
}
Then it's initiated once when the controller starts.
I am trying to create a page that shows a list of products with filtering and multiple ways of sorting the list. Rather than repeating the filtering code for each sort, I wanted to start each of the sorting methods with a call to the filtering method. I can currently filter by name:
filterText: '',
filteredResults: function() {
var filterText = this.get('filterText');
var regexp = new RegExp(filterText,'gi');
var causes = this.get('model.products').filter(function(name){
return name.get('name').match(regexp);
});
return causes;
}.property('filterText'),
However I now want to use this function in the sort methods. I've tried using Ember.computed.sort :
priceAscSorting: ['price'],
sortPriceAsc: Ember.computed.sort('filteredResults', 'priceAscSorting'),
but it seems like it treats the first input as null if I stick it in a template. If I try calling the filter method inside the sorting method:
priceAscSorting: ['views'],
sortPriceAsc: function() {
var products = filteredResults();
}
Ember throws a compiler error saying 'filteredResults' is not defined. How can I access my filter methods to use in my sorting methods?
Your code is correct, it will take filteredResults computed property and return sorted result in ascending order by using price key.
priceAscSorting: ['price'],
sortPriceAsc: Ember.computed.sort('filteredResults', 'priceAscSorting'),
but it seems like it treats the first input as null if I stick it in a
template
that means you need to check filteredResults computed property
My html content is as follows:
<span>{{queries['q1_name'].parameters.length}}</span> <!--Not working: Doesn't show length of parameters-->
My javascript object is as follows:
$scope.queries = {"q1_name":
{"parameters":
{"P1":"abc" }
}
}
This could be done by creating a function, but I am trying to get the length directly in html.
your object should've been: I'm assuming you will be having more than one items in queries since you were using queries[0].parameters.length. if not then you can take out the outer most square brackets.
$scope.queries = [{"parameters":
[{"P1":"abc" },{"P2":"xyz" }]
},{"parameters":
[{"P1":"bcd" },{"P2":"jfk" }]
}];
if "q1_name" is a must have then you need to use queries[0].q1_name.parameters.length. but with this method all of your objects in the array needs to have "q1_name" as property for the code to work on all element in the array.
$scope.queries = [{"q1_name":
{"parameters":
[{"P1":"abc" },{"P2":"xyz" }]
}
}]
Hope that helps.
Given a data structure that contains an array of JavaScript objects, how can I bind a certain entry from that array to an input field using Angular?
The data structure looks like this:
$scope.data = {
name: 'Foo Bar',
fields: [
{field: "F1", value: "1F"},
{field: "F2", value: "2F"},
{field: "F3", value: "3F"}
]
};
The fields array contains several instances of the given structure, with each entry having both a field attribute and a value attribute.
How can I bind an input control to the value field attribute of the array entry with the field F1?
<input ng-model="???"/>
I know that I could bind all fields using an ng-repeat, but that's not what I want. The above data is just an example from a much larger list of fields, where I only want to bind a pre-defined subset of fields to controls on the screen. The subset is not based on the attributes in the array entries, but is known at design time of the page.
So for the above example, I would try to bind F1 to one input on the page, and F2 to another one. F3 would not be bound to a control.
I've seen examples where a function was used in the ng-model, but it doesn't seem to work with Angular 1.1.0.
Is there another clever way to bind the input field to a specific array entry?
Here's a fiddle that has an example, but does not work since it's trying to use function in the ng-model attribute: http://jsfiddle.net/nwinkler/cbnAU/4/
Update
Based on the recommendation below, this is what it should look like: http://jsfiddle.net/nwinkler/cbnAU/7/
I personally would reorganize the array in a way that field property of an entry of the array become the identifier of the object. Mhhh that sentence may sound strange. What I mean is the following:
$scope.data = {
name: 'F1',
fields: {
F1: {
value: "1F"
},
F2: {
value: "2F"
}
}
};
If you want to bind a the value dynamically and it's an easy and quick way to achieve it.
Here is your fiddle modified so that it words. http://jsfiddle.net/RZFm6/
I hope that helps
You can use an array of objects, just not an array of strings.
HTML:
<div ng-repeat="field in data.fields">
<input ng-model="field.val"/>
</div>
JS:
$scope.data = {
name: 'F1',
fields: [
{ val: "v1" },
{ val: "v2" }
]
};
I've updated #Flek's fiddle here: http://jsfiddle.net/RZFm6/6/
Edit: Sorry just read your question properly, you can still use an array with:
<label>Bound to F1:</label>
<input ng-model="data.fields[0].value"/>
though maybe stop and think. Is there going to be variable number of fields ? or are you making a predetermined number of fields ? Use an array in the former and an object for the latter.
One way to do it is to simply add the necessary references to the scope, like this:
$scope.fieldF1 = fieldValue('F1');
$scope.fieldF2 = fieldValue('F2');
And then use those references:
<input ng-model="fieldF1.value"/>
<input ng-model="fieldF2.value"/>
Fiddle: http://jsfiddle.net/cbnAU/5/
Note: I'm assuming that $scope.data is static, but if it happens to be dynamic you can always watch for changes on it and recalculate the references...