30

I have been trying to define directives so I can display different "widgets" in a form, depending on the type of field and its parameters, which are stored in a database. I need to react to different types of scenarios, hence the need for directives to handle layout.

While playing with a few examples, I came up with a code that *kinda* works:

HTML

<input type="text" ng-model="myModel" style="width: 90%"/>  
<div class="zippy" zippy-title="myModel"></div>

Directive

myApp.directive('zippy', function(){
    return {
      restrict: 'C',
      // This HTML will replace the zippy directive.
      transclude: true,
      scope: { title:'=zippyTitle' },
      template: '<input type="text" value="{{title}}"style="width: 90%"/>',
      // The linking function will add behavior to the template
      link: function(scope, element, attrs) {
            // Title element
            element.bind('blur keyup change', function() {
                scope.$apply(read);
            });

            var input = element.children();


            function read() {
                scope.title = input.val();
            }
        }
    }
});

This seems to works (albeit noticeably slower than a *proper* angularJS variable binding) but I figure there must be a better way to do this. Can anyone shed some light on the matter?

2
  • Just curious, I know you didn't end up needing to call $apply manually, but why were you binding both blur and change? Isn't that redundant? If not, I'd be curious to know what the difference is from just using keyup blur. Commented Feb 9, 2013 at 16:38
  • blur and change are different, but I believe for practical purposes, keyup and change are functionally similar. The only diference would be that if I changed the input's value programmatically, using change would trigger an event (the input's data changing), whereas leaving change out would make such a change invisible, unless it came from a keystroke. Bear in mind this was "ages" ago, I had no idea what I was doing with the awesome beast that is angularJS ;) Commented Feb 11, 2013 at 0:51

3 Answers 3

27

I don't know why you are triggering the $apply method manually because you actually don't need it.

I edited the example you used from the Angular page and included the input. It works for me: http://jsfiddle.net/6HcGS/2/

HTML

<div ng-app="zippyModule">
  <div ng-controller="Ctrl3">
    Title: <input ng-model="title">
    <hr>
    <div class="zippy" zippy-title="title"></div>
  </div>
</div>​

JS

function Ctrl3($scope) {
  $scope.title = 'Lorem Ipsum';
}

angular.module('zippyModule', [])
  .directive('zippy', function(){
    return {
      restrict: 'C',
      replace: true,
      transclude: true,
      scope: { title:'=zippyTitle' },
      template: '<input type="text" value="{{title}}"style="width: 90%"/>',
      link: function(scope, element, attrs) {
        // Your controller
      }
    }
  });

UPDATE maxisam is right, you have to use ng-model instead of binding the variable against the value like so:

<input type="text" ng-model="title" style="width: 90%"/>

Here is the working version: http://jsfiddle.net/6HcGS/3/

Sign up to request clarification or add additional context in comments.

3 Comments

It doesn't, it works one way only (as is in the angular docs' examples). What I'm atempting is a two way data-binding scenario - change the $scope value and the directive's value updates, change the directive's value and the $scope value updates. LUCKY NOTE - Brian Ford from the angularJS team kinda answers this, here: youtube.com/watch?feature=player_embedded&v=8_7K6bud5kw
@TiagoRoldão maxisam is right, I just updated my post and the jsfiddle
Great! The keyword "title" is confusing though.. Could you update your fiddle renaming "title" to something like "innerTitle", so that the binding between an inner and an outer variable (in a directive) is clear?
11

You mean something like this ?

I basically use @Flek's example.
The only difference being ng-model='title'

The trick to doing two-way binding is ng-model, and it states in the document:

ngModel is directive that tells Angular to do two-way data binding. It works together with input, select, textarea. You can easily write your own directives to use ngModel as well.

<input type="text" ng-model="title" style="width: 90%"/>

1 Comment

You are right thank! :) I updated my post and included the corrected jsfiddle!
3

Here's a way to pass to a callback parameter in a directive. The controller template:

    <component-paging-select-directive
            page-item-limit="{{pageItemLimit}}"
            page-change-handler="pageChangeHandler(paramPulledOutOffThinAir)"
            ></component-paging-select-directive>

The directive:

angular.module('component')
    .directive('componentPagingSelectDirective', [
        function( ) {
            return {
                restrict: 'E',
                scope: { 
                    // using the '=' for two way doesn't work
                    pageItemLimit:  '@', // the '@' is one way from controller
                    pageChangeHandler: '&'
                },
                controller: function($scope) {   
                    // pass value from this scope to controller method. 
                    // controller method will update the var in controller scope
                    $scope.pageChangeHandler({
                        paramPulledOutOffThinAir: $scope.pageItemLimit
                    })

                }, ...

In the controller:

angular.module('...').controller(...
        $scope.pageItemLimit = 0; // initial value for controller scoped var

        // complete the data update by setting the var in controller scope 
        // to the one from the directive
        $scope.pageChangeHandler = function(paramPulledOutOffThinAir) {
            $scope.pageItemLimit = paramPulledOutOffThinAir;
        }

Note the difference in function parameters for the directive (an object with parameter as keys), template ('unwrapped' keys from the parameter object in directive), and controller definition.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.