Binding to correct model - with same name - angularjs

I have an ng-repeat that displays 2 forms (the array has 2 items)
I have an empty input for each of these, that has the same model, something like the following:
<div ng-repeat=“group in groups”>
<form>
<input type=“text” ng-model=“group.name” placeholder=“name” />
</form>
</div>
Now this works well, until I try to enter text into the first input, it automatically enters into the second as well.
Is there an easy way to bind to the input i’m actually typing in?
Thanks

Your PLNKR example doesn't match your question.
Simplifying your code:
<!-- Top loop doesn't repeat -->
<div ng-repeat="group in groups">
<div ng-repeat="g in group">
<div ng-repeat="info in g.info.data">
<input ng-model="info.name" placeholder="Name" />
</div>
<!-- This is the problem -->
<input ng-model="test.name" placeholder="Name">
<button ng-click="nameAdd($parent.$index)">
Add
</button>
</div>
</div>
The input with the Add button uses the same ng-model name. Also here are three nested loops when only two are needed.
The Data
$scope.groups = {
"data": [{
"id": 1,
"name": "Group 1",
"site_id": 3,
"info": {
"data": [{
"id": 1,
"name": "Jim"
}]
}
}, {
"id": 2,
"name": "Group 2",
"site_id": 3,
"info": {
"data": [{
"id": 10,
"name": "Bob"
}, {
"id": 11,
"name": "Terry"
}]
}
}]
}
Change the template to:
<!-- remove top loop
<div ng-repeat="group in groups">
-->
<div ng-repeat="groupDatum in groups.data" ng-cloak>
<div ng-repeat="infoDatum in groupDatum.info.data">
<input ng-model="infoDatum.name" placeholder="Name" />
</div>
<!-- use groupDatum to store new name -->
<input ng-model="groupDatum.newName" placeholder="Name">
<!-- use groupDatum as arg to ng-click -->
<button ng-click="nameAdd(groupDatum)">
Add
</button>
</div>
The nameAdd function:
$scope.nameAdd = function(groupDatum) {
var newId = uniqueId();
var newName = groupDatum.newName;
groupDatum.info.data.push({id: newId, name: newName});
}

try like this,
<div ng-repeat=“group in groups”>
<form>
<input type=“text” ng-model=“groups[$index].name” placeholder=“name” />
</form>
</div>
you also probably put the form tag outside of the repeater unless you want to create a new from for every input tag

Related

Angular setting default radio selection in ng-repeat

I am presenting a simple yes/no answer question to my users and I want to have a default radio button selected. The problem is that I could have any number of these questions presented to the user.
This is my code:
<div ng-form ng-repeat="i in offers track by $index" name="messageForm[$index]">
<div data-ng-repeat="option in closeListingOptions" class="radio">
<label>
<input type="radio" name="close" ng-model="i.close" value="{{option.id}}" ng-checked="option.checked" />{{option.name}}</strong>
</label>
</div>
</div>
My options are set as follows:
$scope.closeListingOptions = [
{
id: "1",
name: "Yes please",
checked: true
},
{
id: "0",
name: "No thanks",
checked: false
}
];
The above example works and check/sets "yes" as the default answer. However unless I manually select an option via a mouse click the value is not binding to the model.
I have read that ng-select should not be used with ng-options but i am not sure how else I can achieve this goal? It seems that I need something like:
i.close = "1":
But how can I set this for an unknown quntity since I don't know how many question will be presented?
1- Instead of value={{something}} you can use ng-value directive.
2- Each input pack should have its specific name.
Here is a working example:
var app = angular.module("app", []);
app.controller("MainCtrl", function($scope) {
$scope.offers = [{
number: 1
},
{
number: 2
}
];
$scope.closeListingOptions = [{
id: "1",
name: "Yes please",
checked: true
},
{
id: "0",
name: "No thanks",
checked: false
}
];
});
<html ng-app="app">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</head>
<body ng-controller="MainCtrl">
<div ng-form ng-repeat="i in offers" name="messageForm[$index]">
<div data-ng-repeat="option in closeListingOptions" class="radio">
<label>
<input type="radio" name="close-{{i.number}}" ng-model="i.close" ng-value="option.id" ng-checked="option.checked" />{{option.name}}</strong>
</label>
</div>
{{i}}
<hr>
</div>
</body>
</html>
You should try this:
<input type="radio" name="close"
ng-model="option.checked" value="{{option.id}}"
ng-checked="option.checked" />{{option.name}}</strong>
This ng-model will updated the checked key of your data array and then you can fetch all the radio button selection as per their ids from that single variable.
Hope this helps.
I was able t achieve my goal with the following:
<div data-ng-repeat="option in closeListingOptions" class="radio" ng-init="i.closeListing = 1">
<label>
<input type="radio" name="close-{{i.id}}" ng-model="i.closeListing" ng-value="{{option.id}}" />
<strong>{{option.name}}</strong>
</label>
</div>
The solution was to use ng-init

Filter data from JSON file by a specific value using angularjs

Currently I have a JSON file look like this:
[
{
"name":"Bánh bao nướng phô mai thịt",
"image":"banhbaonuongphomaithit",
"howtocook":"<h1>abc<\/h1>",
"video":"sY6bswxfVGM",
"category": "bakery"
},
{
"name":"Cháo móng giò hạt sen",
"image":"chaomonggiohatsen",
"howtocook":"Sample",
"video":"24vqCAXlQ0w",
"category": "appetizer"
},
{
"name":"Bánh mì chà bông nhân trứng muối",
"image":"banhmichabongnhantrungmuoi",
"howtocook":"Sample",
"video":"HhMj6jDIQrY",
"category": "bakery"
},
{
"name":"Cà chua muối kiểu kim chi",
"image":"cachuamuoikieukimchi",
"howtocook":"Sample",
"video":"aOYlyEiV3HQ",
"category": "appetizer"
}
]
This is my JS
var pageControllers = angular.module('pageControllers', [])
.config(function($sceProvider) {
// Completely disable SCE. For demonstration purposes only!
// Do not use in new projects or libraries.
$sceProvider.enabled(false);
});
;
pageControllers.controller('HomeController', ['$scope', '$http', function($scope, $http) {
$http.get('js/foods.json').success(function(data) {
$scope.games = data;
});
}]);
And HTML
<div class="row"> <!--First row-->
<div class="col-xs-12 col-sm-4 col-lg-3" ng-repeat = "item in games | filter: query">
<img ng-src="img/foods/{{item.image}}.png" alt="{{item.name}}">
<div class="caption">
<h5 class="text-center" ng-model="foodname">{{item.name}}</h5>
<form name="uploadItem" ng-submit="addFavorite()" novalidate ng-controller = "UploadController" ng-show = "currentUser" ng-controller = "RegistrationController">
<div class="form-group">
<input type="text" name="name" class="form-control" ng-model="foodname" ng-init="foodname='{{item.name}}'" value="{{item.name}}" >
</div>
<button type="submit" class="btn btn-block" style="background-color: #FF4500">Add to favorite</button><br>
</form>
</div>
</div><!--End of first row-->
</div>
And I want to display every records filter by category, for example when I filter appetizer or making it in a category page, all records that have appetizer category should displayed. I've though about reorganize the JSON file but still do not know how to filter it.
You should use .then and access data property
pageControllers.controller('HomeController', ['$scope', '$http', function($scope, $http) {
$http.get('foods.json').then(function(data) {
$scope.games = data.data;
});
}]);
DEMO
Add a search box to filter results by a property say 'category' as :
<input type="text" ng-model="query.category" placeholder="Search by category"/>
In this, the ng-model="query.category" would filter the ng-repeat="item in games | filter: query " on the category type
DEMO
angular.module('pageControllers', []).controller('HomeController', ['$scope', function($scope) {
$scope.games = [{
"name": "Bánh bao nướng phô mai thịt",
"image": "banhbaonuongphomaithit",
"howtocook": "<h1>abc<\/h1>",
"video": "sY6bswxfVGM",
"category": "bakery"
},
{
"name": "Cháo móng giò hạt sen",
"image": "chaomonggiohatsen",
"howtocook": "Sample",
"video": "24vqCAXlQ0w",
"category": "appetizer"
},
{
"name": "Bánh mì chà bông nhân trứng muối",
"image": "banhmichabongnhantrungmuoi",
"howtocook": "Sample",
"video": "HhMj6jDIQrY",
"category": "bakery"
},
{
"name": "Cà chua muối kiểu kim chi",
"image": "cachuamuoikieukimchi",
"howtocook": "Sample",
"video": "aOYlyEiV3HQ",
"category": "appetizer"
}
]
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<div class="row" ng-app="pageControllers" ng-controller="HomeController">
<!--First row-->
<input type="text" ng-model="query.category" placeholder="Search by category"/>
<br> <br> <br>
<div class="col-xs-12 col-sm-4 col-lg-3" ng-repeat="item in games | filter: query ">
<img ng-src="img/foods/{{item.image}}.png" alt="{{item.name}}">
<div class="caption">
<h5 class="text-center" ng-model="foodname">{{item.name}}</h5>
<form name="uploadItem" ng-submit="addFavorite()" novalidate ng-show="currentUser">
<div class="form-group">
<input type="text" name="name" class="form-control" ng-model="foodname" ng-init="foodname='{{item.name}}'" value="{{item.name}}">
</div>
<button type="submit" class="btn btn-block" style="background-color: #FF4500">Add to favorite</button><br>
</form>
</div>
</div>
<!--End of first row-->
</div>
Thank for your kindness.
I found a way to filter the data in JSON file by category, i just need to put filter: {category:'bakery'} in the ng-repeat
ng-repeat = "item in foods | filter: query | filter: {category:'bakery'}"

Why is my ng-repeat is only displaying first result?

I have this array of an array of objects that I am pushing onto from results I pass from a modal;
[
[
{
"id": 4,
"name": "THROTTLE TUBE",
"partno": "104-",
"oemnumber": "46019 038",
"stock": 19,
"price": "28"
},
{
"id": 28,
"name": "TACHOMETER, CUP",
"partno": "128-",
"oemnumber": "25012 011",
"stock": 7,
"price": "46"
}
]
]
I am getting this from the following;
$scope.woParts = [];
//later in my modal code - which is where the double [] is coming from
modalInstance.result.then(function(woParts) {
$scope.woParts.push(woParts);
I am then using this ng-repeat in my view;
<div ng-repeat="woPart in woParts">
<div class="col-md-4">
#{{ woPart[$index].name }}
</div>
<div class="col-md-2">
#{{ woPart[$index].oemnumber }}
</div>
<div class="col-md-2">
#{{ woPart[$index].price | currency}}
</div>
<div class="col-md-2">
<input type="number"
class="form-control"
ng-model="partQty">
</div>
</div>
This only displays the first result in the array. Why is that?
Thanks!
I don't think you should push woParts into another object. Just save it to the scope: $scope.woParts = woParts;. Then there is no need to use $index in the ngRepeat, just use regular dot notation: woPart.name.
Or if you have to push woParts into another array, then you can change the ngRepeat expression to woPart in woParts[0].

ng-change not firing when switching between ng-includes

My domain is such that Bars have Groups. The following code allows the user to pick a Bar (outputted to {{selected.bar.name}}). Users are to choose a Bar.
If a Group only has one Bar then the Bar is presented at the top level (step-0), otherwise the user can drill down into the Group and select the Bar from there (step-1).
In the below code, Bar 1 and Bar 2 are their only ones in their group, whilst Bar 3 and Bar 4 share a group, Group 3.
Everything works well apart from the following sequence:
Select Group 3
Select any Bar
Click Previous
Select any other Bar
Selecting Group 3 again does not take you to step-1 again; the ng-change event is not fired.
(function(ng) {
'use strict';
ng.module('awesome', [])
.controller('BarController', [
'$scope',
function($scope) {
$scope.bars = [{
"id": 1,
"name": "Bar 1",
"group": "Group 1"
}, {
"id": 2,
"name": "Bar 2",
"group": "Group 2"
}, {
"id": 3,
"name": "Bar 3",
"group": "Group 3"
}, {
"id": 4,
"name": "Bar 4",
"group": "Group 3"
}];
$scope.currentTab = 'step-0';
$scope.previousTab = null;
$scope.goBack = function() {
$scope.currentTab = $scope.previousTab;
$scope.previousTab = null;
}
$scope.groupedBars = _.groupBy($scope.bars, 'group');
$scope.selected = {}
$scope.availableGroupedBars = $scope.groupedBars;
$scope.availableBars = $scope.bars;
$scope.groupSelected = function(group) {
console.log('groupSelected');
$scope.currentTab = 'step-1';
$scope.previousTab = 'step-0';
$scope.availableBars = group;
}
}
]);
})(window.angular);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.1/underscore-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="awesome">
<div ng-controller="BarController">
<div ng-include="currentTab"></div>
Selected bar name: {{selected.bar.name}}
<button ng-show="previousTab" ng-click="goBack()">Previous</button>
</div>
<script type="text/ng-template" id="step-0">
<ul>
<li ng-repeat="(key, group) in availableGroupedBars">
<label ng-switch="group.length">
<span ng-switch-default>{{key}}</span>
<input ng-switch-default type="radio" name="group" ng-model="selected.group" ng-value="group" ng-change="groupSelected(selected.group)" />
<span ng-switch-when="1">{{group[0].name}}</span>
<input ng-switch-when="1" type="radio" name="group" ng-model="selected.bar" ng-value="group[0]" />
</label>
</li>
</ul>
</script>
<script type="text/ng-template" id="step-1">
<ul>
<li ng-repeat="bar in availableBars">
<label>
{{bar.name}}
<input type="radio" name="bar" ng-model="selected.bar" ng-value="bar" required />
</label>
</li>
</ul>
</script>
</div>
How can I make the ng-change event for Group 3 fire once returning to step-0?
The change event is not fired because nothing changes. You only have one group and that group is still selected when you go back. It stays selected forever, i.e the value of $scope.selected.group never changes, regardless of what radio button you choose.
The ngChange expression is only evaluated when a change in the input value causes a new value to be committed to the model.
I strongly suggest to rethink your approach. If you don't want to then you can add an ng-change to your bars in step-0 and clear $scope.selected.group whenever a bar is selected.
$scope.clearGroup = function() {
$scope.selected.group = null;
};
<input ng-switch-when="1" type="radio" name="group"
ng-model="selected.bar" ng-value="group[0]"
ng-change="clearGroup()" />

Cascading select data binding

First look at my fiddle
JavaScript:
function CountryCntrl($scope) {
$scope.filters = {};
$scope.categories = [{
"id": 1,
"title": "Company",
"children": [{
"id": 2,
"title": "About",
"children": [{
"id": 6,
"title": "Company profile",
"children": [],
"isRoot": false
}],
"isRoot": false
} ..
}
HTML:
<div class="row" ng-controller="CountryCntrl">
<div class="col-lg-12">
<h4>Filter by:</h4>
</div>
<div class="col-lg-12">
<form>
<div class="row">
<div class="col-xs-4" ng-repeat="cat in categories" ng-if="cat.isRoot==true">
<div class="form-group">
<select ng-if="cat.isRoot==true" class="form-control" ng-model="filters.rootCat" ng-options="sub_cat.title for sub_cat in cat.children track by sub_cat.id">
<option value="">level 1 - {{$index}}</option>
</select>
</div>
<div class="form-group">
<select class="form-control" ng-model="filters[cat.id]" ng-options="sub_sub_cat.title for sub_sub_cat in filters.rootCat.children track by sub_sub_cat.id">
<option value="">level 2 - {{$index}}</option>
</select>
</div>
</div>
</div>
</form>
</div>
</div>
I'm not able to display the options of the select of the second level only, related to the first level.
In my fiddle you can see that you change the value of "level 1-0" the select below "level 2 - 0" is correctly populated but is binded the "level 2 - 6" too...
What's wrong ?
The problem is that you have an ng-repeat in which you use the same object as model for each item repeated, which means they will conflict and affect each other.
The simplest solution is probably to change filters.rootCat to filters['rootCat'+$index].
That way you ensure that each column of dropdowns have their own model.

Resources