2

I have a custom directive, and its purpose is to present a widget and bind it to a variable. Every variable has different data type, so different widgets will be presented depending on the data type.

My problem is that I can pass the data of the variable, but I can't manage to bind the widget to it.

To simplify the problem, my widget is just a simple text input. When I try to $compile the widget, Angular uses the value of the variable instead of binding to it.

HTML:

<body ng-app="app" ng-controller="myCtrl">
  <input type="text" ng-model="resource.name"></div>
  <div custom-widget widget-type="widget" bind-to="resource"></div>
</body>

Javascript:

angular.module('app', [])
  .directive('customWidget', function($compile) {
    return {
      replace: true,
      template: '<div></div>',
      controller: function($scope) {

      },
      scope: {
        bindTo: "=bindTo",
        widgetType: "=widgetType"
      },
      link: function(scope, iElem, iAttrs) {
        var html = '<div>' + scope.widgetType.label + ':<input ng-bind="' + scope.bindTo[scope.widgetType.id] + '" /></div>';
        iElem.replaceWith($compile(html)(scope));
      }
    };
  })
  .controller('myCtrl', function($scope) {
    $scope.widget = {
      id: 'name',
      label: 'Text input',
      type: 'text'
    };
    $scope.resource = {
      name: 'John'
    };
  });

Plunker demo: http://plnkr.co/edit/qhUdNhjSN7NlP4xRVcEA?p=preview

I'm still new to AngularJS and my approach may not be the best, so any different ideas are of course appreciated!

2
  • what do you want to achieve is not clear Commented Dec 5, 2013 at 18:14
  • in the Plunker demo, I want the 2 fields to be two-way-binded to $scope.resource.name Commented Dec 5, 2013 at 18:26

2 Answers 2

1

Since you're using an isolate scope one issue is that resource is on the parents scope and not visible within the directive. And I think you're looking for ng-model rather than ng-bind.

Also, since you want to bind to namein resource, we need to tie that in somehow.

So here's one approach to your template html (note the addition of $parent to get around the scope issue and the addition of .name(which you could add programatically using a variable if you preferred, or specify it as part of the attribute))

var html = '<div>' + scope.widgetType.label + ':<input ng-model="' + '$parent.' + iAttrs.bindTo +'.name'+ '" /></div>';

Updated plunker

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

1 Comment

Thanks! Can you please explain what $parent means? Does it just points to the parent scope of the current one?
0

Well, when you have a isolated scope within your directive and use the "=" operator you already have two-way data binding.

My suggestion would be to use the "template" more like a view so the operations are clearer.

I would change your directive to the following:

Using ng-model instead of ng-bing mainly because as the Documentation reveals:

The ngModel directive binds an input,select, textarea (or custom form control) to a property on the scope using NgModelController, which is created and exposed by this directive. [...]

Changed directive:

angular.module('app', [])
  .directive('customWidget', function($compile) {
    return {
      replace: true,
      template: '<div> {{widgetType.label}} <input ng-model="bindTo[widgetType.id]" /></div>',
      scope: {
        bindTo: "=bindTo",
        widgetType: "=widgetType"
      }
   };
 });

EDIT: Ops forgot the Updated Plunker

2 Comments

It is a lot clearer, but my main goal is to have different custom widgets, depending on the type of the data. Is it possible to have different templates depending on widgetType.type?
@GuyB7 Hmm, got it. Well it is possible to change the template according to the type, but that would involve using $http and $compile in the linking function to get the url's of the different widget (like this dude suggests), or maybe take a look at the ngInclude directive. Sorry if it didn't help much, best of luck! Cheers.

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.