ng-change not firing when switching between ng-includes - angularjs

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()" />

Related

How to show a particular div based on radio box checked in angularjs

I have radio buttons and 'delete' text with ng repeat,here based on radio button checked I need to show the delete text,whenever I click on radio button 'delete' text should show and again when I click to next radio button 'delete' should hide for previous unchecked radio button and should show for next checked radio button.
For me its working but onclick of next radio button previous 'delete' text is not hiding.Code is given below.Can anyone help me I am new to angularjs.
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.div_ = [];
$scope.items = [{
id: 1,
title: "first item"
},
{
id: 2,
title: "second item",
},
{
id: 3,
title: "third item",
}
];
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.11/angular.min.js"></script>
<script src="app.js"></script>
<div ng-app="plunker" ng-controller="MainCtrl">
<ul ng-repeat="item in items">
<li style="color:red;display:inline" ng-click="item=1"><input type="radio" name="samename" value={{$index}}></li>
<li style="color:blue;display:inline;margin-left:100px;" name="samenaame" ng-show="item==1" ng-show="item==1">delete</li>
</ul>
</div>
I tried to do minimum amount of changes to your main code, but I think it is flawed.
Not sure what you are trying to achieve with the multiple ul's you had, so I removed them.
You can use ng-repeat-start and -end as in this example, maybe that's what you want.
This code will only show one extra "li" depends on which ID you selected. (using a "helper" property)
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.div_ = [];
$scope.selectedItem;//or nothing
$scope.items = [{
id: 1,
title: "first item"
},
{
id: 2,
title: "second item",
},
{
id: 3,
title: "third item",
}
];
$scope.handleClick = function (item) {
$scope.selectedItem = item;
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.11/angular.min.js"></script>
<div ng-app="plunker" ng-controller="MainCtrl">
<ul>
<li ng-repeat-start="item in items" style="color:red;display:inline" ng-click="handleClick(item)">#Item={{item.id}}
<input type="radio" name="samename" value={{$index}}>
</li>
<li ng-repeat-end style="color:blue;display:inline;margin-left:100px;" ng-show="selectedItem==item">delete #{{item.id}}</li>
</ul>
</div>

Track by index doesnt reset after changing selection

i have a cascading select option, and is working well, the problem is that when i change the first selected option, in the second selection option (subcategory), it keeps the index. So case i change the category (first select), in the second selection it goes to the option position that it was.
For better understanding, please check this example i made and try changin the options. You will notice that in the second selec option keeps the position index that had in the previous category selected. It doesnt starts to 0 when changing the category.
Link: http://jsfiddle.net/Fqfg3/28/
Js:
var app = angular.module('app', []);
app.controller('PeopleCtrl', function ($http,$scope) {
vm = this;
vm.options = [
{
"_id": "1",
"label": "Category 1",
"childs": [
"Category 1 -> Subcategory 1",
"Category 1 -> Subcategory 2",
"others"
]
},
{
"_id": "2",
"label": "Category 2",
"childs": [
"Category 2 -> Subcategory 1",
"Category 2 -> Subcategory 2",
"others"
]
},
{
"_id": "3",
"label": "Category 3",
"childs": [
"Category 3 -> Subcategory 1",
"Category 3 -> Subcategory 2",
"others"
]
}];
});
html:
<div ng-app="app" ng-controller="PeopleCtrl as ctrl" class="container">
{{ctrl.options}}
<div class="form-group question-wrapper">
<select class="form-control"
name="category"
ng-options="option.label for option in ctrl.options track by option._id"
ng-model="ctrl.supportMail.selected">
</select>
</div>
<div class="form-group question-wrapper">
<select id="sub" class="form-control"
name="subcategory"
>
<option ng-repeat="child in ctrl.supportMail.selected.childs track by $index">{{child}}</option>
</select>
</div>
</div>
You can use ng-change in main select to reset the subselect to default.
Here's is a demonstration working:
(function() {
"use strict";
angular.module('app', [])
.controller('mainCtrl', function() {
var vm = this;
vm.options = [
{
"_id":"1",
"label":"Category 1",
"childs":[
"Category 1 -> Subcategory 1",
"Category 1 -> Subcategory 2",
"others"
]
},
{
"_id":"2",
"label":"Category 2",
"childs":[
"Category 2 -> Subcategory 1",
"Category 2 -> Subcategory 2",
"others"
]
},
{
"_id":"3",
"label":"Category 3",
"childs":[
"Category 3 -> Subcategory 1",
"Category 3 -> Subcategory 2",
"others"
]
}
];
vm.reset_subSelect = function() {
vm.supportMail.child = vm.supportMail.selected.childs[0];
}
});
})();
<!DOCTYPE html>
<html ng-app="app">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js" type="text/javascript"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" type="text/javascript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.min.js"></script>
</head>
<body ng-controller="mainCtrl as ctrl">
<div class="container">
<div class="form-group question-wrapper">
<select class="form-control" name="category" ng-options="option.label for option in ctrl.options track by option._id" ng-model="ctrl.supportMail.selected" ng-change="ctrl.reset_subSelect()" ng-init="ctrl.supportMail.selected = ctrl.options[0]">
</select>
</div>
<div class="form-group question-wrapper">
<select class="form-control" id="sub" name="subcategory" ng-options="child for child in ctrl.supportMail.selected.childs" ng-model="ctrl.supportMail.child" ng-init="ctrl.supportMail.child = ctrl.supportMail.selected.childs[0]">
</select>
</div>
</div>
</body>
</html>
I hope it helps.
By adding an ng-model to your subcategory I was able to resolve the issue you can see the example here
Hope this helps.

Binding to correct model - with same name

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

Display Groupname with selected item on Dropdown using angularjs?

This is my Code
var app = angular.module('myExample', []);
function myCtrl($scope) {
$scope.myOptions = [{
"id": 106,
"group": "Employee",
"label": "Id"
},{
"id": 107,
"group": "Employee",
"label": "Name"
},{
"id": 110,
"group": "Department",
"label": "Id"
}];
$scope.getSelectedField=function(){
//$scope.myOption=$scope.myOption;
alert($scope.myOption);
};
};
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-controller="myCtrl">
<select
ng-model="myOption"
ng-options="value.group+'.'+value.label as value.label group by value.group for value in myOptions" ng-change="getSelectedField()" >
<option>--</option>
</select>
<div>
selected value: {{myOption}}
</div>
</div>
The above code selected Item display on dropdown , But I want to display Groupname with Selected Item on Dropdown.for example when user select id now display 'Employee.id' on Dropdown.
Try
Here value.group+'.'+value.label will display on dropdown. Before you were displaying only value.label.
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-controller="myCtrl">
<select
ng-model="myOption"
ng-options="value.group+'.'+value.label as value.group+'.'+value.label group by value.group for value in myOptions" ng-change="getSelectedField()" >
<option>--</option>
</select>
<div>
selected value: {{myOption}}
</div>
</div>

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