I have multiple select boxes and I'm using angular JS. Each select box needs to have a different selected value. So far everything I've seen has elements that share the same selected value. In order to achieve this a scope is used. Since I can potentially have hundreds of drop downs... actually thousands... what is the correct approach here? Create a scope for each one? Try to have one scope that mutates with each select box?Here is an example with what I have jsfiddle.Any help is much appreciated.
Thanks
function MyCntrl($scope) {
$scope.colors = [
{name:'black'},
{name:'red'},
{yellow:'yellow'}
]
$scope.isSel = $scope.colors[1];
}
You need to bind each select box to its own scope. You can do it manually, binding each one to a new object instead of the same isSel, or you can use a ng-repeat like so:
http://jsfiddle.net/zmU8R/9/
html:
<div ng-app="">
<div ng-controller="MyCntrl">
<div ng-repeat="control in controls">
<select ng-model="control.isSel" ng-options="c.name for c in colors"></select><br />
</div>
<hr />
<div ng-repeat="control in controls">
{{control.id}}: {{control.isSel}}
</div>
</div>
</div>
script:
function MyCntrl($scope) {
$scope.controls = [
{id: 1, isSel:null},
{id: 2, isSel:null},
{id: 3, isSel:null}
];
$scope.colors = [
{name:'black'},
{name:'red'},
{name:'yellow'}
];
}
Not sure I've figured out what you exactly want. As far as I understand, you need each selectbox to have different value. So, you need to bind each selectbox to a different variable.
<div ng-app="myApp">
<div ng-controller="myCtrl">
<hr/>
<div ng-repeat="n in [] | range: selectionsCount">
<select ng-model="selectedValues[$index]" ng-options="c.name for c in colors"></select>
</div>
{{ selectedValues }}
</div>
</div>
For a much clearer example, I made selectboxes count variable here.
angular.module('myApp', [])
.controller('myCtrl', function ($scope) {
$scope.colors = [
{name: 'black'},
{name: 'red'},
{name: 'yellow'}
];
$scope.selectedValues = [];
$scope.selectionsCount = 5;
})
.filter('range', function () {
return function(input, total) {
total = parseInt(total);
for (var i=0; i<total; i++)
input.push(i);
return input;
};
});
You can test it here: http://jsfiddle.net/zmU8R/7/
If I misunderstood your question, feel free to correct me.
Related
Right now my data structure is like
product = [{att1:'2',att2:'red',att3:'gold'},
{att1:'1',att2:'blue',att3:'wood'},
{att1:'2',att2:'green',att3:'plastic'},
{att1:'1',att2:'red',att3:'plastic'}]
And I have a filter on the web page, it has three parts: att1, att2, att3. The user doesn't have to choose options for every part.
For filter att1 it has 2 options: "1" and "2".
Filter att2 it has 2 options: "red" "blue" and "green"
Filter att3 it has 3 options: "gold", "wood" and "plastic".
I can get the options that are selected. For example:
{att1:['2'],att3:['gold','plastic']} or {att1:['1']}
My question is, how do I use product.filter to filter the product data?
Thanks!
You can use a custom filter function which is easy to use, I used att1 but you can expand it to all fields:
var app = angular.module("MyApp", []);
app.controller("MyCtrl", function($scope) {
$scope.products = [{att1:'2',att2:'red',att3:'gold'},
{att1:'1',att2:'blue',att3:'wood'},
{att1:'2',att2:'green',att3:'plastic'},
{att1:'1',att2:'red',att3:'plastic'}];
$scope.filterFunction = function(element) {
return element.att1.match(/^Ma/) ? true : false;
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="MyApp">
<div ng-controller="MyCtrl">
<form class="form-inline">
<input ng-model="query" type="text"
placeholder="Filter by" autofocus>
</form>
<ul ng-repeat="product in products | filter:query">
<li>{{product}}</li>
</ul>
<ul ng-repeat="product in products | filter:filterFunction">
<li>{{product}}</li>
</ul>
</div>
</div>
I banged out the particular logic for this one, using the three nested loops isn't super great but it does do the job. I'm sure you can optimize this further by using some maps or something but I just went with the get it done by brute force approach :)
angular.module('myApp',[])
.service('ProductService', function(){
return {
products:[
{att1:'2',att2:'red',att3:'gold'},
{att1:'1',att2:'blue',att3:'wood'},
{att1:'2',att2:'green',att3:'plastic'},
{att1:'1',att2:'red',att3:'plastic'}
]
}
})
.controller('TestCtrl', function(ProductService){
this.ProductService = ProductService;
this.filterObject1 = {att1:['2'],att3:['gold','plastic']};
this.filterObject2 = {att1:['1']};
})
.filter('productFilter', function(){
return function(input,filterObj){
if(!filterObj){
return input;
}
var newArray = [];
var filterKeys = Object.keys(filterObj);
for(var i=0;i<input.length;i++){
var curElement = input[i];
innerLoops:
for(var j=0;j<filterKeys.length;j++){
var curKey= filterKeys[j];
for(var k=0;k<filterObj[curKey].length;k++){
var curFilterValue = filterObj[curKey][k];
if(curElement[curKey].match(curFilterValue)){
//We found a match keep this element and move on to checking the next one by breaking out of the inner loops that are checking particular keys/values
newArray.push(curElement);
break innerLoops;
}
}
}
}
return newArray;
};
})
;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.6/angular.js"></script>
<div ng-app="myApp" ng-controller="TestCtrl as ctrl">
Unfiltered
<div ng-repeat="product in ctrl.ProductService.products|productFilter">
{{product}}
</div>
<hr/>
<strong>Filtered with: {{ctrl.filterObject1}}</strong>
<div ng-repeat="product in ctrl.ProductService.products|productFilter:ctrl.filterObject1">
{{product}}
</div>
<hr/>
<strong>Filtered with {{ctrl.filterObject2}}</strong>
<div ng-repeat="product in ctrl.ProductService.products|productFilter:ctrl.filterObject2">
{{product}}
</div>
</div>
I'm trying to use md-chips to collect input from user with auto-complete. For ex: price,available,Y,N. where each component will be rendered in chips.There will be multiple inputs from user per line. When i submit the form i need all the chips per line entered by user. This is where i'm facing the problem.
<div ng-repeat ="rule in rules">
<md-chips ng-model="selectedHeaders">
<md-chip-template>
{{$chip}}
</md-chip-template>
</md-chips>
</div>
the above code works as my model is just selectheader and in js it's
$scope.selectedHeaders = [];
how should i use it to for rule.selectheader??. If i change my model to rule.selectheader , it throws this below error
Cannot set property 'selectedHeaders' of undefined.
Any pointers to solve this issue will be much apppreciated. If issue is not clear, please ask
Have you defined rules values?
In js, at least the value of rules must be something like this
var rules = [{
selectedHeaders: ['Apple', 'Orange']
}, {
selectedHeaders: ['Banana']
}];
you can do like below
Js code
var app = angular.module('myApp', []);
app.controller('ctrl1', function($scope) {
$scope.rules = [{
name: 'rule1',
id: 1
}, {
name: 'rule2',
id: 2
}];
$scope.data = {};
});
HTML
<div ng-app='myApp'>
<div ng-controller='ctrl1'>
<div ng-repeat="rule in rules">
<md-chips ng-model="data.selectedHeaders">
<md-chip-template>
{{$chip}}
<!-- for testing-->{{rule}}
</md-chip-template>
</md-chips>
</div>
</div>
</div>
Here is the link Jsfiddle demo
I am trying to use check list where ng-model will bind the selected data based on two dynamic value.
My code is:
<div ng-repeat="individualFieldInfo in formInatiatingData">
<div ng-repeat="individualListItem in individualFieldInfo.list"
<input type="checkbox" ng- model=
"userGivenData[individualFieldInfo.fieldName][individualListItem.value]">
{{individualListItem}}
</div>
</div>
Here,
userGivenData[individualFieldInfo.fieldName][individualListItem.value]"
is not workng.
My JSON is:
$scope.userGivenData={
}
$scope.formInatiatingData = [
{
type:"checkList",
fieldName:"Fruit",
list : [
{
id:1,
value:"mango"
},
{
id:2,
value:"Banana"
},
{
id:3,
value:"Jackfruit"
}
]
}
]
For single dynamic binding userGivenData[individualFieldInfo.fieldName] is working. But, for two dynamicvalues, its not working.
I am searching for a way where if a user check a checkbox, it will be binded in userGivenData.fieldName.value
angular.module('myApp', [])
.controller('MyController', function($scope){
$scope.someComplex = {
someInnerObj: {
thisIsAProperty: 'withSomeValue'
}
};
$scope.thing1 = 'someInnerObj';
$scope.thing2 = 'thisIsAProperty';
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyController">
<pre>{{someComplex|json}}</pre>
<pre>{{someComplex[thing1][thing2]}}</pre>
<input type="text" ng-model="someComplex[thing1][thing2]"/>
</div>
In a test case this does work... can you output some more of the data objects values you show there like I did in the sample here using the json filter and pre tags?
I have some simple data from which I'd like to create dynamic ng-model names from. I know that if you have those names handy you concatenate their input values together and display them, like so:
<p>{{blah--bleh}}</p>
But what if I don't know those ng-model names in advance, or how many there will be? How can I dynamically create those names and then for however many are created display the sum of their values that the user inputs?
If its not clear what I'm asking, here is a fiddle. I think you'll see what I'm going for.
The html
<div ng-controller="MainCtrl">
<ul>
<li ng-repeat="invoice in invoices">
<input type="number" step="any" placeholder="Enter Amount"
ng-model="invoice.salesOrder" />
</li>
</ul>
<div class="sum"> Total Amount: ${{blah--blah}}
</div><!-- READ ONLY -->
</div>
The js
var app = angular.module('angularjs-starter', [])
.controller("MainCtrl",
function($scope) {
$scope.invoices = [
{
"salesOrder": "5"
},
{
"salesOrder": "6"
},
{
"salesOrder": "7"
}
];
});
Make a function like so: http://jsfiddle.net/d5ug98ke/2/
This will calculate the total and update the bound variable anytime an input changes
<div ng-controller="MainCtrl">
<ul>
<li ng-repeat="invoice in invoices">
<input type="number" step="any" placeholder="Enter Amount"
ng-model="invoice.salesOrder" ng-change="getSalesTotal()" />
</li>
</ul>
<div class="sum"> Total Amount: ${{sum}}
</div><!-- READ ONLY -->
</div>
var app = angular.module('angularjs-starter', [])
.controller("MainCtrl",
function($scope) {
$scope.sum = 0;
$scope.invoices = [
{
"salesOrder": "5"
},
{
"salesOrder": "6"
},
{
"salesOrder": "7"
}
];
$scope.getSalesTotal = function(){
$scope.sum = 0;
$scope.invoices.forEach(function(invoice){
$scope.sum += parseInt(invoice.salesOrder, 10);
});
};
});
I have a requirement to implement an editable list for a project I am working on. When you click on an item it changes to an edit state that has a bunch of options related to the item you clicked on. Our UX wants the items to be edited in-line but I am not sure of the best way to do this in angular and would like to know which way is better.
Example 1 Template
<div class="person" ng-repeat="person in people" ng-click="editing=!editing">
<div class="details-view" ng-hide="editing" ng-bind="person.name"></div>
<div class="edit-view" ng-show="editing">
<input type="text" /> <button type="button">Save</button> <a>Cancel</a>
</div>
</div>
Example 1 Controller
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.people = [
{name: 'Joe', age:23},
{name: 'Jim', age:32},
{name: 'Jill', age:13}
]
});
The first way (example here) is to have an ng-repeat and inside of each ng-repeat item create an edit mode that is specific to the ng-repeat item. This works great but I don't want to leave edit mode until I have a successful response from the server and I don't understand how to handle that using this method.
Example 2 Template
<div class="person" ng-repeat="person in people" ng-click="toggleEditing(person)">
<div class="details-view" ng-hide="person.editing" ng-bind="person.name"></div>
<div class="edit-view" ng-show="person.editing">
<input type="text" /> <button type="button">Save</button> <a>Cancel</a>
</div>
</div>
Example 2 Controller
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.people = [
{name: 'Joe', age:23},
{name: 'Jim', age:32},
{name: 'Jill', age:13}
];
$scope.toggleEditing = function(person) {
person.editing = !person.editing;
};
});
The second way (example here) I thought of is to duck punch the view state onto the object. I don't like this way because I don't want to modify the object handed to me by the ng-repeat.This method does allow me to handle the successful save that the first way above doesn't.
Are there any better options?
If you don't want to clutter the object with the view state, you can save the view state in an different object.
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.editedItems = {};
$scope.people = [
{name: 'Joe', age:23},
{name: 'Jim', age:32},
{name: 'Jill', age:13}
];
$scope.toggleEditing = function(person) {
$scope.editedItems[person.name] =
!$scope.editedItems[person.name] || true;
};
});
HTML
<div class="person" ng-repeat="person in people" ng-click="toggleEditing(person)">
<div class="details-view" ng-hide="editedItems[person.name]" ng-bind="person.name"></div>
<div class="edit-view" ng-show="editedItems[person.name]">
<input type="text" /> <button type="button">Save</button> <a>Cancel</a>
</div>
</div>
Have you tried ng-grid instead of ng-repeat? They have a good edit in-line model and it seems to have better UX than the ng-hide/ng-show options.