admin管理员组文章数量:1332352
Html:
Filter:
<input type="radio" ng-model="Type" value="Rear"> Rear
<input type="radio" ng-model="Type" value="Front"> Front
<br>
Select:
<name-value-select entry="entry" field="axleType" options="filterTypes"></name-value-select>
Directive:
.directive('nameValueSelect', function () {
return {
restrict: "E",
scope: {
entry: "=",
field: "@",
options: "=",
onInputChange: "&"
},
controller: function ($scope) {
$scope.onChange = function () {
console.log("selected changed");
$scope.entry.type = $scope.option.value;
$scope.onInputChange();
};
var getItemForValue = function (value) {
var item = null;
$scope.options.forEach(function (_option) {
if (_option.value == value) {
item = _option;
}
});
return item;
};
$scope.$watch("entry", function () {
console.log("entry changed");
$scope.option = getItemForValue($scope.entry[$scope.field]);
}, true);
},
template: '<select ng-model="option" ng-options="o.Description for o in options" ng-change="onChange()"><option value="" selected="selected">Please Select </option></select>'
}; })
Controller:
$scope.Description = '';
$scope.entry = {Description: ''};
$scope.Type = 'Front';
$scope.entry.type = '';
$scope.$watch('Type', function (Type) {
$scope.filterTypes = [];
$scope.axleTypes = new API.GetAxleTypes(function () {
angular.forEach($scope.axleTypes, function(axleType) {
if (axleType.Type == Type) {
this.push(axleType);
}
// if(!$scope.$$phase) $scope.$digest(); // tried this, does not have any affect
}, $scope.filterTypes); // '}, $scope.filterTypes, true)'--> did nothing for me here
});
$scope.filterTypes.sort(function (a, b) {
return a.Description.localeCompare(b.Description);
});
}); // '}, true)' --> did nothing for me here
Problem:
The custom select control does initially populate with items of Type 'Front', and would also populate with 'Rear' if I made Rear the default.
However, when toggling between radio buttons, the watch function is not called and the select does not populate with items meeting newly selected filter type.
////////////////////////////////////////////////////// Narrowed Down the Problem: /////////////////////////////////////////////////////
When moving this to a stand alone project, I discovered my code above works :-(
Here is the original select NOT as a custom directive:
<select ng-model="$parent.selectedFrontAxle" ng-options="axleType.Description for axleType in axleTypes | filterByType: 'Front' | orderBy:'Description'" id="frontAxles" class="formRequire" required>
<option value="" selected>Select Axle Type ..</option>
</select>
Here is the select control as a custom directive:
<name-value-select entry="entry" field="axleType" options="filterTypes"></name-value-select>
Clearly this is the issue: "ng-model="$parent.selectedFrontAxle"
If I take the directive "name-value-select" and move it to the parent page, in lieu of a include statement, it works.
But that is not what I want. So I need to leave it in the include page.
Yet, if I take the ng-model="$parent.selectedFrontAxle" and add it to ANY element on the include page, nothing works.
Any with no ng-model="$parent.selectedFrontAxle", still nothing works.
I can see the issue is scope yet I do not see how to correct it.
Ughh!!! Still no solution.
//
//
//////////////////////////////////////////////////////////////
Mark Rajcok
//////////////////////////////////////////////////////////////
As always thanks for your help. Although, I do not think I made myself clear on point 2 when I said I had scenarios where I wanted the code to pre-filter and not the user. I figured it out though. So for anyone looking to abstract out controls via a directive, and, as in this case, where a filtering process is performed both by the user and in code, here is the plunker solution:
Html:
Filter:
<input type="radio" ng-model="Type" value="Rear"> Rear
<input type="radio" ng-model="Type" value="Front"> Front
<br>
Select:
<name-value-select entry="entry" field="axleType" options="filterTypes"></name-value-select>
Directive:
.directive('nameValueSelect', function () {
return {
restrict: "E",
scope: {
entry: "=",
field: "@",
options: "=",
onInputChange: "&"
},
controller: function ($scope) {
$scope.onChange = function () {
console.log("selected changed");
$scope.entry.type = $scope.option.value;
$scope.onInputChange();
};
var getItemForValue = function (value) {
var item = null;
$scope.options.forEach(function (_option) {
if (_option.value == value) {
item = _option;
}
});
return item;
};
$scope.$watch("entry", function () {
console.log("entry changed");
$scope.option = getItemForValue($scope.entry[$scope.field]);
}, true);
},
template: '<select ng-model="option" ng-options="o.Description for o in options" ng-change="onChange()"><option value="" selected="selected">Please Select </option></select>'
}; })
Controller:
$scope.Description = '';
$scope.entry = {Description: ''};
$scope.Type = 'Front';
$scope.entry.type = '';
$scope.$watch('Type', function (Type) {
$scope.filterTypes = [];
$scope.axleTypes = new API.GetAxleTypes(function () {
angular.forEach($scope.axleTypes, function(axleType) {
if (axleType.Type == Type) {
this.push(axleType);
}
// if(!$scope.$$phase) $scope.$digest(); // tried this, does not have any affect
}, $scope.filterTypes); // '}, $scope.filterTypes, true)'--> did nothing for me here
});
$scope.filterTypes.sort(function (a, b) {
return a.Description.localeCompare(b.Description);
});
}); // '}, true)' --> did nothing for me here
Problem:
The custom select control does initially populate with items of Type 'Front', and would also populate with 'Rear' if I made Rear the default.
However, when toggling between radio buttons, the watch function is not called and the select does not populate with items meeting newly selected filter type.
////////////////////////////////////////////////////// Narrowed Down the Problem: /////////////////////////////////////////////////////
When moving this to a stand alone project, I discovered my code above works :-(
Here is the original select NOT as a custom directive:
<select ng-model="$parent.selectedFrontAxle" ng-options="axleType.Description for axleType in axleTypes | filterByType: 'Front' | orderBy:'Description'" id="frontAxles" class="formRequire" required>
<option value="" selected>Select Axle Type ..</option>
</select>
Here is the select control as a custom directive:
<name-value-select entry="entry" field="axleType" options="filterTypes"></name-value-select>
Clearly this is the issue: "ng-model="$parent.selectedFrontAxle"
If I take the directive "name-value-select" and move it to the parent page, in lieu of a include statement, it works.
But that is not what I want. So I need to leave it in the include page.
Yet, if I take the ng-model="$parent.selectedFrontAxle" and add it to ANY element on the include page, nothing works.
Any with no ng-model="$parent.selectedFrontAxle", still nothing works.
I can see the issue is scope yet I do not see how to correct it.
Ughh!!! Still no solution.
//
//
//////////////////////////////////////////////////////////////
Mark Rajcok
//////////////////////////////////////////////////////////////
As always thanks for your help. Although, I do not think I made myself clear on point 2 when I said I had scenarios where I wanted the code to pre-filter and not the user. I figured it out though. So for anyone looking to abstract out controls via a directive, and, as in this case, where a filtering process is performed both by the user and in code, here is the plunker solution:
http://plnkr.co/edit/tnXgPKADfr5Okvj8oV2S?p=preview
Share Improve this question edited Sep 29, 2015 at 11:51 munity wiki15 revs, 2 users 100%
Bye 6
- 1 its better if you set up plunker or fiddle demo for the problem – Ajay Singh Beniwal Commented Apr 23, 2013 at 4:50
- Mark see above ment addressed to you. – Bye Commented Apr 23, 2013 at 16:15
-
You don't want the same controller twice/nested. Can you set up a Plunker (using ng-include)? Or at least show where you are using ng-include? It is not clear which HTML is being ng-included. I also don't understand what
$scope.Type
and$scope.entry.type
are for. If your directive is supposed to be watching the radio buttons change, then the radio buttons need to useentry.type
. Also,on-input-change
is not specified in your HTML, so your `&' binding won't work in the directive. (BTW, I did not get notified of your ment above... you need to use @Mark.) – Mark Rajcok Commented Apr 23, 2013 at 18:20 - @MarkRajcok, see ments above sNJ dude – Bye Commented Apr 23, 2013 at 18:54
- @MarkRajcok you there? – Bye Commented Apr 24, 2013 at 13:50
2 Answers
Reset to default 4In this plunker, I reworked the code to allow the user to select either "Rear" or "Front", and the select list will dynamically update. The selected value is available as $scope.selected.item
on the MainCtrl scope. (There was a lot of unnecessary code in the directive that I removed. onChange handlers aren't needed when ng-model is being used.)
<name-value-select selected-item="selected.item" options="filterTypes">
</name-value-select>
app.directive('nameValueSelect', function () {
return {
restrict: "E",
scope: {
selectedItem: "=",
options: '='
},
template: ...
Since ng-include creates a child scope, all primitive properties were converted to object properties, so that JavaScript prototypal inheritance will work as expected (i.e., when values are changed, $scope objects defined in the MainCtrl get changed rather than new primitive properties being created on local scopes).
I believe the plunker referenced above will satisfy your "point 1".
I will now look at creating a plunker for "point 2"... (I'll add a ment when I update this answer).
This plunker filters the select list in the directive:
<name-value-select selected-item="selected.item" choice="choice.type"
options="myTypes"></name-value-select>
app.directive('nameValueSelect', function () {
return {
restrict: "E",
scope: {
selectedItem: "=",
choice: "=",
options: "=",
},
controller: function($scope) {
$scope.$watch('choice', function (selectedType) {
$scope.selectedItem = ''; // clear selection
$scope.filterTypes = [];
angular.forEach($scope.options, function (type) {
if (type.Type === selectedType) {
this.push(type);
}
}, $scope.filterTypes);
$scope.filterTypes.sort(function (a, b) {
return a.Description.localeCompare(b.Description);
});
});
},
template: '<select ng-model="selectedItem" ' +
'ng-options="o.Description for o in filterTypes">' +
'<option value="" selected="selected">Please Select</option>' +
'</select>'
};
});
I do not exactly understand your request, but I just assume that you want to dynamically change the content of a select according to the value a radio button group. The select is filtered and sorted and you may choose which field of the data to display.
You may have a look at this Plunker which contains a demo with few modifications.
HTML
Filter:
<input type="radio" ng-model="filter.type" value="rear"> Rear
<input type="radio" ng-model="filter.type" value="front"> Front
<br />
Field:
<select ng-model="filter.field" ng-options="item for item in fields"></select>
<br />
Select:
<select ng-model="entry" ng-options="item[filter.field] for item in entries | filter:type=filter.type | orderBy:filter.field">
<option value="">Default</option>
</select>
<br />
Selected: <span>{{entry}}</span>
<h2>Alternative</h2>
Filter: <span>{{filter}}</span>
<br />
<select ng-model="altentry" ng-options="item[filter.field] for item in altentries | orderBy:filter.field">
<option value="">Default</option>
</select>
<br />
Selected: <span>{{altentry}}</span>
JS
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
/* Default filter values */
$scope.filter = {
type: 'rear',
field: 'name'
};
/* List of fields */
$scope.fields = [
"id", "type", "name"
];
/* Data ing from an API */
$scope.entries = [
{"id":1, "type":"rear", "name":"Rear Part 01"},
{"id":2, "type":"rear", "name":"Rear Part 03"},
{"id":3, "type":"rear", "name":"Rear Part 05"},
{"id":4, "type":"rear", "name":"Rear Part 02"},
{"id":5, "type":"rear", "name":"Rear Part 04"},
{"id":6, "type":"front", "name":"Front Part 01"},
{"id":7, "type":"front", "name":"Front Part 03"},
{"id":8, "type":"front", "name":"Front Part 05"},
{"id":9, "type":"front", "name":"Front Part 02"},
{"id":10, "type":"front", "name":"Front Part 04"},
];
/* Simulate different ajax return */
$scope.$watch('filter.type', function(newval, oldval) {
if (newval || newval !== oldval) {
$scope.altentries = [];
angular.forEach($scope.entries, function(v,k) {
if (v.type === $scope.filter.type) {
$scope.altentries.push(v);
}
});
}
});
/* Monitoring any selected value */
$scope.$watch('entry', function(newval, oldval) {
console.log('entry:', oldval, newval);
}, true);
$scope.$watch('altentry', function(newval, oldval) {
console.log('altentry:', oldval, newval);
}, true);
});
本文标签: javascriptAngularJSwatch not triggered on change (scope issue with include page)Stack Overflow
版权声明:本文标题:javascript - AngularJS : $watch not triggered on change ($scope issue with include page) - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742321660a2452911.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论