AngularJS 指令作用域变量未定义
AngularJS Directive Scope variables undefined
这是相关的 JSFiddle
https://jsfiddle.net/9Ltyru6a/3/
在 fiddle 中,我设置了一个控制器和一个指令,我想在值发生变化时使用它来调用回调。我知道 Angular 有一个 ng-change 指令,但我想要更类似于标准 onchange 事件的东西(当字段模糊时触发一次)。
控制器:
var Controllers;
(function (Controllers) {
var MyCtrl = (function () {
function MyCtrl($scope) {
$scope.vm = this;
}
MyCtrl.prototype.callback = function (newValue) {
alert(newValue);
};
return MyCtrl;
})();
Controllers.MyCtrl = MyCtrl;
})(Controllers || (Controllers = {}));
指令:
var Directives;
(function (Directives) {
function OnChange() {
var directive = {};
directive.restrict = "A";
directive.scope = {
onchange: '&'
};
directive.link = function (scope, elm) {
scope.$watch('onChange', function (nVal) {
elm.val(nVal);
});
elm.bind('blur', function () {
var currentValue = elm.val();
scope.$apply(function () {
scope.onchange({ newValue: currentValue });
});
});
};
return directive;
}
Directives.OnChange = OnChange;
})(Directives || (Directives = {}));
HTML:
<body ng-app="app" style="overflow: hidden;">
<div ng-controller="MyCtrl">
<button ng-click="vm.callback('Works')">Test</button>
<input onchange="vm.callback(newValue)"></input>
</div>
</body>
按钮有效,所以我可以放心地说(我认为)控制器没问题。但是,每当我更改输入字段的值并取消焦点时,我都会收到 "vm is undefined" 错误。
感谢您的帮助!
首先,使用正确的controllerAs表示法,而不是$scope.vm = this;
:
ng-controller="MyCtrl as vm"
然后不要将自定义指令与本机 onchange
事件处理程序混合使用 - 这就是您收到 undefined
错误的原因。将您的指令命名为 onChange
并改用 on-change
属性。
正确的代码如下:
var app = angular.module("app", []);
var Directives;
(function (Directives) {
function OnChange() {
var directive = {};
directive.restrict = "A";
directive.scope = {
onChange: '&'
};
directive.link = function (scope, elm) {
elm.bind('blur', function () {
var currentValue = elm.val();
scope.$apply(function () {
scope.onChange({
newValue: currentValue
});
});
});
};
return directive;
}
Directives.onChange = OnChange;
})(Directives || (Directives = {}));
app.directive("onChange", Directives.onChange);
var Controllers;
(function (Controllers) {
var MyCtrl = (function () {
function MyCtrl($scope) {
}
MyCtrl.prototype.callback = function (newValue) {
alert(newValue);
};
return MyCtrl;
})();
Controllers.MyCtrl = MyCtrl;
})(Controllers || (Controllers = {}));
app.controller("MyCtrl", ["$scope", function ($scope) {
return new Controllers.MyCtrl($scope);
}]);
如果您的代码的目的是仅在模糊时更新您的控制器值,而不是在每次按键时更新它,angular 有 ngModelOptions
用于此用途。例如:
<input type="text" ng-model="user.name" ng-model-options="{ updateOn: 'blur' }" />
您甚至可以提供去抖动或清除值的按钮....
<form name="userForm">
<input type="text" name="userName"
ng-model="user.name" ng-model-options="{ debounce: 1000 }" />
<button ng-click="userForm.userName.$rollbackViewValue(); user.name=''">Clear</button>
</form>
在这些情况下,如果您要提供 ng-change
,它只会在模糊事件或去抖之后触发。
您还可以编写直接利用 ngModelController
中的 $validators
或 $asyncValidators
的指令
这是来自 Angular Developer Guide 的示例:
app.directive('username', function($q, $timeout) {
return {
require: 'ngModel',
link: function(scope, elm, attrs, ctrl) {
var usernames = ['Jim', 'John', 'Jill', 'Jackie'];
ctrl.$asyncValidators.username = function(modelValue, viewValue) {
if (ctrl.$isEmpty(modelValue)) {
// consider empty model valid
return $q.when();
}
var def = $q.defer();
$timeout(function() {
// Mock a delayed response
if (usernames.indexOf(modelValue) === -1) {
// The username is available
def.resolve();
} else {
def.reject();
}
}, 2000);
return def.promise;
};
}
};
});
和 HTML:
<div>
Username:
<input type="text" ng-model="name" name="name" username />{{name}}<br />
<span ng-show="form.name.$pending.username">Checking if this name is available...</span>
<span ng-show="form.name.$error.username">This username is already taken!</span>
</div>
您当然可以添加 ng-model-options
以确保只触发一次。
这是相关的 JSFiddle
https://jsfiddle.net/9Ltyru6a/3/
在 fiddle 中,我设置了一个控制器和一个指令,我想在值发生变化时使用它来调用回调。我知道 Angular 有一个 ng-change 指令,但我想要更类似于标准 onchange 事件的东西(当字段模糊时触发一次)。
控制器:
var Controllers;
(function (Controllers) {
var MyCtrl = (function () {
function MyCtrl($scope) {
$scope.vm = this;
}
MyCtrl.prototype.callback = function (newValue) {
alert(newValue);
};
return MyCtrl;
})();
Controllers.MyCtrl = MyCtrl;
})(Controllers || (Controllers = {}));
指令:
var Directives;
(function (Directives) {
function OnChange() {
var directive = {};
directive.restrict = "A";
directive.scope = {
onchange: '&'
};
directive.link = function (scope, elm) {
scope.$watch('onChange', function (nVal) {
elm.val(nVal);
});
elm.bind('blur', function () {
var currentValue = elm.val();
scope.$apply(function () {
scope.onchange({ newValue: currentValue });
});
});
};
return directive;
}
Directives.OnChange = OnChange;
})(Directives || (Directives = {}));
HTML:
<body ng-app="app" style="overflow: hidden;">
<div ng-controller="MyCtrl">
<button ng-click="vm.callback('Works')">Test</button>
<input onchange="vm.callback(newValue)"></input>
</div>
</body>
按钮有效,所以我可以放心地说(我认为)控制器没问题。但是,每当我更改输入字段的值并取消焦点时,我都会收到 "vm is undefined" 错误。
感谢您的帮助!
首先,使用正确的controllerAs表示法,而不是$scope.vm = this;
:
ng-controller="MyCtrl as vm"
然后不要将自定义指令与本机 onchange
事件处理程序混合使用 - 这就是您收到 undefined
错误的原因。将您的指令命名为 onChange
并改用 on-change
属性。
正确的代码如下:
var app = angular.module("app", []);
var Directives;
(function (Directives) {
function OnChange() {
var directive = {};
directive.restrict = "A";
directive.scope = {
onChange: '&'
};
directive.link = function (scope, elm) {
elm.bind('blur', function () {
var currentValue = elm.val();
scope.$apply(function () {
scope.onChange({
newValue: currentValue
});
});
});
};
return directive;
}
Directives.onChange = OnChange;
})(Directives || (Directives = {}));
app.directive("onChange", Directives.onChange);
var Controllers;
(function (Controllers) {
var MyCtrl = (function () {
function MyCtrl($scope) {
}
MyCtrl.prototype.callback = function (newValue) {
alert(newValue);
};
return MyCtrl;
})();
Controllers.MyCtrl = MyCtrl;
})(Controllers || (Controllers = {}));
app.controller("MyCtrl", ["$scope", function ($scope) {
return new Controllers.MyCtrl($scope);
}]);
如果您的代码的目的是仅在模糊时更新您的控制器值,而不是在每次按键时更新它,angular 有 ngModelOptions
用于此用途。例如:
<input type="text" ng-model="user.name" ng-model-options="{ updateOn: 'blur' }" />
您甚至可以提供去抖动或清除值的按钮....
<form name="userForm">
<input type="text" name="userName"
ng-model="user.name" ng-model-options="{ debounce: 1000 }" />
<button ng-click="userForm.userName.$rollbackViewValue(); user.name=''">Clear</button>
</form>
在这些情况下,如果您要提供 ng-change
,它只会在模糊事件或去抖之后触发。
您还可以编写直接利用 ngModelController
$validators
或 $asyncValidators
的指令
这是来自 Angular Developer Guide 的示例:
app.directive('username', function($q, $timeout) {
return {
require: 'ngModel',
link: function(scope, elm, attrs, ctrl) {
var usernames = ['Jim', 'John', 'Jill', 'Jackie'];
ctrl.$asyncValidators.username = function(modelValue, viewValue) {
if (ctrl.$isEmpty(modelValue)) {
// consider empty model valid
return $q.when();
}
var def = $q.defer();
$timeout(function() {
// Mock a delayed response
if (usernames.indexOf(modelValue) === -1) {
// The username is available
def.resolve();
} else {
def.reject();
}
}, 2000);
return def.promise;
};
}
};
});
和 HTML:
<div>
Username:
<input type="text" ng-model="name" name="name" username />{{name}}<br />
<span ng-show="form.name.$pending.username">Checking if this name is available...</span>
<span ng-show="form.name.$error.username">This username is already taken!</span>
</div>
您当然可以添加 ng-model-options
以确保只触发一次。