问题
I'm trying to create a directive that will list all the errors contained in an errors object ({phone: ["is required"]
}, but only if the object is non-empty. (It doesn't make sense to say "The following errors…" when there were none.)
I figured out how to check if an object is empty by testing Object.keys(errors).length
. The problem is that I can't figure out how to access Object.keys from my directive template. Is this possible?
Since Angular expressions are "evaluated" (using $parse
, not eval()
) in the context of a scope
instead of in the context of window
, we don't have access to things like Object
from the directives template, because Object
isn't a property of the scope. (Docs: Expressions)
Makes sense so far. It goes on to say that "Unlike JavaScript, where names default to global window
properties, Angular expressions must use $window
explicitly to refer to the global window
object. For example, if you want to call alert()
in an expression you must use $window.alert()
.
But I can't seem to access Object
even if I do $window.Object
. What am I missing?
Here's the code for the directive I'm debugging (and here's a jsfiddle):
app.js.coffee:
…
.directive 'displayErrorsAllKeys', ->
{
restrict: 'A',
scope: {
errors: '='
debug: '@debug'
}
templateUrl: 'templates/display-errors-all-keys'
}
.run(['$rootScope', ($rootScope) ->
$rootScope.nonEmpty = (object) ->
!! Object.keys(object).length
])
.controller('TestDisplayErrorsAllKeys',
['$scope',
( $scope ) ->
$scope.other_errors = {}
$scope.add_errors = ->
$scope.other_errors = {"surname":["is required"],"phone":["is required"]}
$scope.clear_errors = ->
$scope.other_errors = {}
])
display-errors-all-keys.ngt.haml:
.errors(ng-show="$window.Object.keys(errors).length > 0")
%p The following errors prevented this from saving:
%div(ng-repeat="(key, error_messages) in errors") {{key}}: {{error_messages | toSentence}}
test_ng_display-errors-all-keys.html.haml
:scss
.errors {
color: red;
}
%div(ng-app='MyApp')
%form(ng-controller="TestDisplayErrorsAllKeys")
%p errors: {{ other_errors }}
%p nonEmpty(other_errors): {{ nonEmpty(other_errors) }}
%hr/
%div(display-errors-all-keys errors="other_errors")
%input(type="button" value="Add errors" ng-click="add_errors()")/
%input(type="button" value="Clear errors" ng-click="clear_errors()")/
I finally got it to work by defining a helper method in my scope and calling that instead ($root.nonEmpty(errors)
) (see jsfiddle for working demo).
This is probably a pretty good solution, but:
Is there an even better way to solve this? How would you have done it (written the
ng-show
expression)?How would I get it to work using
Object.keys(errors).length
directly in theng-show
??
回答1:
I would provide the helper function in the directives scope (which is isolated). Typically by providing a link function for the directive:
.directive('displayErrorsAllKeys', function() {
return {
restrict: 'A',
scope: {
errors: '=',
debug: '@debug'
},
link: function (scope) {
scope.errorsExists = function(object) {
return object && Object.keys(object).length;
};
},
templateUrl: 'templates/display-errors-all-keys'
};
})
Placing logic and data in the root scope is seldom a good practice. Also note that I named the function errorExists, which provides som abstraction upon the actual representation of the errors.
As for your second question, you could add scope.Object = Object;
in your link function, but DON'T! Such specific logic doesn't belong in your template. The template should be concerned with wether or not to show the errors, but not why.
回答2:
Here's a nonEmpty
filter I added to solve this problem (JavaScript equivalent)
.filter 'nonEmpty', ->
(object) ->
!! (object && Object.keys(object).length > 0)
Tests:
%div {{ null | nonEmpty }} should be false
%div {{ { } | nonEmpty }} should be false
%div {{ {a: '1'} | nonEmpty }} should be true
My ng-show condition in the example above can be simplified to just this:
ng-show="errors | nonEmpty"
Now I can easily reuse this check logic, without having to add a new method to each directive or controller where I may want to use it.
来源:https://stackoverflow.com/questions/22852388/how-do-i-access-object-keysobject-length-from-a-directive-template