下面是一些代码,用于在使用类名和jquery通过ng-show隐藏模型的相应输入时清除角度模型值,但它有一种难闻的气味bc它在控制器中操纵DOM(编辑 - 它没有操纵DOM它改变了范围模型值,但我并不是疯狂使用jquery)。这样做是否有“棱角分明的方式”?
我应该补充一点,下面的代码只是为了证明解决方案是可能的概念验证。实际项目有非常复杂的业务规则来显示具有许多逻辑分支的部分,子部分和子部分......所以很难在@New Dev建议的情况下在手表中编写该逻辑......此外,我不想在两个地方都有逻辑:在所有显示和隐藏AND的div中都有... ...
<!doctype html>
<html xmlns:ng="http://angularjs.org" ng-app="app">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
</head>
<body ng-controller="MainCtrl">
<div style="padding:20px; background-color:silver;color:blue">{{person | json }}</div>
Name: <input ng-model="person.name" name="name" >
<div ng-show="person.name.length">
Age: <input ng-model="person.age" name="age" class="hide-clear">
<div ng-show="person.age.toString().length">
Hobby: <input ng-model="person.hobby" name="hobby" class="hide-clear">
</div>
</div>
<Script>
angular.module('app', [])
.controller('MainCtrl', function($scope,$log,$timeout){
$scope.person = {
name: 'mr smith',
age: 51,
hobby: 'coding'
}
$scope.$watchCollection(
//return the value to be watched
function($scope){
return $scope.person
},
//function to be called when changed
function(newValue,oldValue){
$timeout( function() {
$(".hide-clear").each(function(){
var t = $(this);
if( ! t.is(":visible") ) {
$scope.person[t.attr('name')] = '';
}
})
})
}
)
})
</Script>
</body>
</html>
答案 0 :(得分:4)
我很高兴您认识到上述方法是一种糟糕的设计(或者#34;难闻的气味&#34;,就像你说的那样)。实际上,Angular方式(或更一般地说,MVVM方式)只是操纵View Model,让View Model驱动View。
例如,当您的父容器被$scope.person.age = ""
隐藏时(即当$scope.person.hobby = ""
为空时),您试图设置ng-show="person.name.length"
和$scope.person.name
。不要使用容器的最终隐形作为指标,而是使用导致容器首先不可见的原始数据。
$scope.$watch("person.name", function(val){
if (val === "") { // or, if (!val.length), to make it completely equivalent
$scope.person.age = "";
$scope.person.hobby = "";
}
});
上面的代码监视$scope.person.name
为空(和/或undefined
,无论您的定义是什么)来设置其他属性。对控制器来说,根本不对空的person.name
做出反应并不重要 - 它本可以完成一些动画或其他UI技巧。该逻辑仅处理视图模型状态。
可以进一步改进上面的代码以避免$watch
,而是对导致$scope.person.name
变空的事件作出反应。在您的示例中,它似乎只是由用户从文本框中删除名称引起的。
<input ng-model="person.name" ng-change="onPersonChanged()">
$scope.onPersonChanged = function(){
if (!$scope.person.name) {
$scope.person.age = "";
$scope.person.hobby = "";
}
};
这比$watch
更可取,因为$watch
会在每个摘要周期触发,而ng-change
只有在输入字段发生变化时才会触发。
答案 1 :(得分:0)
以下是我最好的尝试。我仍然使用jquery来检测元素是否可见,并且该指令不使用隔离范围,但至少所有逻辑都包含在两个指令中,这些指令允许在其他项目中重用:
指令代码(clearmModelWhenHidden.js)
angular.module('clearModelWhenHidden', [])
.directive('clearModelWhenHiddenContainer', function() {
return {
scope: false,
controller: function($scope, $parse, $timeout) {
$scope.registeredElements = [];
//since we dont' have an isolate scope, namespace our public API to avoid collision
this.clearModelWhenHidden = {};
//to share a method with child directives use the "this" scope and have children require the parent controller...
this.clearModelWhenHidden.register = function(e) {
$scope.registeredElements.push(e);
}
$scope.$watchCollection(
function() {
//convert the registered elements ng-model attribute from a string to an angular
//object that can be watched for changes
var parsedArray = [];
angular.forEach($scope.registeredElements, function(item, i) {
parsedArray.push($parse(item.attributes.ngModel)($scope))
});
return parsedArray;
},
function(newvalue) {
$timeout(function() {
angular.forEach($scope.registeredElements, function(item, i) {
var isVisible = $(item.element).is(':visible');
if (!isVisible) {
var value = $parse(item.attributes.ngModel)($scope);
//create a string that sets the ng-model of each element to an empty string,
//for example, person.name=''
var stringToEval = item.attributes.ngModel + '="" ';
console.log(stringToEval)
$parse(stringToEval)($scope);
}
})
});
}
);
}
}
})
.directive('clearModelWhenHidden', function() {
var link = function(scope, element, attributes, parentController) {
//pass in the element itself so we can used jquery to detect visibility and the attributes so the container can create a watch on the models
parentController.clearModelWhenHidden.register({
'element': element[0],
'attributes': attributes
});
}
return {
link: link,
require: '^clearModelWhenHiddenContainer'
}
})
和演示页
<!doctype html>
<html xmlns:ng="http://angularjs.org" ng-app="app">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0-alpha1/jquery.min.js" type="text/javascript"></script>
<script language="javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.3/angular.js"></script>
<script language="javascript" src="clearModelWhenHidden.js"></script>
</head>
<body ng-controller="MainCtrl as MainCtrl">
<div style="padding:20px; background-color:silver;color:blue">{{MainCtrl.person | json }}</div>
<div clear-model-when-hidden-container>
<section>
Name:
<input ng-model="MainCtrl.person.name" clear-model-when-hidden>
<div ng-show="MainCtrl.person.name.length">
<label>Age</label>:
<input ng-model="MainCtrl.person.age" clear-model-when-hidden>
<section ng-if="MainCtrl.person.age.toString().length">
<label>Hobby</label>:
<input ng-model="MainCtrl.person.hobby" clear-model-when-hidden>
</section>
</div>
</section>
</div>
</body>
</html>