问题
This is an AngularJS widget which replaces a tag with an editable text field. Clicking the text replaces it with an input field, and hitting enter on the input updates an existing resource.
I am not happy with the code I produced. Are all of these evals and applys really necessary? How can I improve this?
To use
editable-text(model="activeCustomer.phone_number", resource="Customer", field="phone_number")
The Directive Code
.directive("editableText", function($injector){
return {
restrict: "E",
templateUrl: document.views.directivePartials.editableText,
link: function(scope, elem, attrs){
$(elem).find(".noEdit").click(function(){
scope.showEdit = true;
scope.$apply();
});
var ENTER = 13;
$(elem).find('.edit').keyup(function(event){
if(event.keyCode == ENTER){
var resource = $injector.get(attrs.resource);
var params = {};
params[attrs.field] = scope.value
resource.update(params);
scope.showEdit=false;
}
});
scope.showEdit = false;
scope.$watch(attrs.model, function(){
scope.value = scope.$eval(attrs.model);
});
},
};
})
The Template
span.editableTextField
input.edit(type="text", ng-show="showEdit", ng-model="value")
span.noEdit(ng-show="!showEdit") {{value}}
回答1:
I would recommend not using jQuery with Angular, especially as you're learning. None of what you're doing requires it.
You can get rid of the first use of
click
callback by usingngClick
in your template:<span class="editableTextField" ng-click="showEdit = true">
You can get rid of the
keyup
callback buy using Angular-UI:<input class="edit" ... ui-keypress="{enter: 'handleEnter()'}">
I'd recommend using a two-way binding so you can write data back to the scope properly.
When you wire up
$watch
, you get the new value as the first argument. That will save you another$eval
.
Here's a fiddle for you... http://jsfiddle.net/maU9t/
回答2:
Fiddle! http://jsfiddle.net/pvtpenguin/25cqs/17
Changes:
Create an
on-enter
directive that theeditable-text
directive uses in the template. The newon-enter
directive can be reused anywhere.<input ... on-enter="update()" ... />
Use the
ng-click
directive to toggleshowEdit
state instead of relying on jquery and a function.<input ... on-click="showEdit = true" ... />
Binds
value
on the directive's isolate scope to the value of the directive's model attribute. This lets us remove thescope.$watch
and creates a two-way binding between the localvalue
andactiveCustomer.phone_number
<editable-text model="activeCustomer.phone_number"></editable-text> <input ... ng-model="value" /> <span>{{value}}</span> ... scope: { // give `value` and `activeCustomer.phone_number two-way binding value: '=model' }
These changes completely remove the jQuery dependency. Resulting directive:
myApp.directive("editableText", function($injector){
return {
restrict: "E",
scope: {
value: '=model' // Bind `value` to what is declared on the `model` attribute
},
templateUrl: "/tpl.html",
link: function(scope, elem, attrs){
scope.update = function() {
var resource = $injector.get(attrs.resource);
var params = {};
params[attrs.field] = scope.value;
resource.update(params);
scope.showEdit=false;
};
scope.showEdit = false;
}
};
});
回答3:
Here is one version of inline editor. http://jsfiddle.net/pUMer/
Key features:
- Configure the initial mode of the inline editor
- Seperate scope for each inline editor, so that it wont interfere with the parent scope
- View the model of all the inline editors
If you want only on inline editor, pls. reduce the array element to size of one.
HTML:
<inline-editor inline-editor-mdl="inlineEditor"></inline-editor>
来源:https://stackoverflow.com/questions/16425012/angular-js-and-complex-directives