0

I'm trying to create a directive to cut down on the boilerplate code that I'd have to write.

I'm using the angular xeditable directive to allow for inline editing, but when I add the xeditable directive attributes from my directive, it doesn't work.

When I say it doesn't work, I mean usually when I click on the element there is an input box that appears, and right now nothing happens when I click on the element.

Glenn.directive('edit', function() {
    return {
        restrict: 'A',
        template: '{{ content.' + 'ParamData' + '.data }}',
        scope: {
            ParamData: '@edit'
        },
        link: function(scope, element, attrs) {     
            element.attr('editable-text', 'content.' + attrs.edit + '.data');
            element.attr('onbeforesave', 'update($data, content.' + attrs.edit +'.id');
        }
    }
});

So, my first problem is that the xeditable directive doesn't work because it's inside of mine. I'm new to creating angularjs directives, but am wondering if it could have something to do with the way its being compiled?

My second problem is with the template. If my template just looks like this

template: '{{ ParamData }}'

Then it outputs the correct data, but I can't make it work without the other pieces to reference the scope data.

Also, here is what the view looks like using the directive

<h2 edit="portrait_description_title"></h2>

And here is what it would look like if I didn't use a directive to cut down on the boiler code

<h1 editable-text="content.portrait_description_title.data" onbeforesave="update($data, content.portrait_description_title.id)">
     {{ content.portrait_description_title.data }}
</h1>

Thanks for any advice!

2
  • You'll need to read up on scopes and transclusion. When you specify scope: {} you are creating a new scope, this is why you can't access the parent scope. Either don't create a child scope, or pass in the required element like you did with ParamData. Use transclusion to nest the directives (similar to how ng-repeat works, for example). Commented Jul 22, 2014 at 23:11
  • Either you would need to recompile the code or (as stated above) use a transclusion and the compiler will make sure to handle the nested directive compilation. Commented Jul 22, 2014 at 23:15

2 Answers 2

2

You have to recompile the element after adding those attributes, here is an example:

Example plunker: http://plnkr.co/edit/00Lb4A9rVSZuZjkNyn2o?p=preview

.directive('edit', function($compile) {
  return {
    restrict: 'A',
    priority: 1000,
    terminal: true, // only compile this directive at first, will compile others later in link function
    template: function (tElement, tAttrs) {
      return '{{ content.' + tAttrs.edit + '.data }}';
    },
    link: function(scope, element, attrs) {
      attrs.$set('editable-text', 'content.' + attrs.edit + '.data');
      attrs.$set('onbeforesave', 'update($data, content.' + attrs.edit + '.id)');
      attrs.$set('edit', null); // remove self to avoid recursion.
      $compile(element)(scope);
    }
  }
});

Things to consider:

  • remove the isolated scope to simplify things as it seems you would like to do the binding directly to a scope in controller content.portrait_description_title.data in the first place.
  • template: also accept function, this way you can get the edit attribute value to construct the template.
  • mark as a terminal directive and raise priority, so that at first run, only this diective (out of others in the same element) will get compiled.
  • attrs.$set() is useful for adding/removing attributes, use it to add the editable-text directive and onbeforesave.
  • remove the directive itself, i.e. the edit attribute, to prevent a recursion after a next compilation.
  • use $compile service to recompile the element, in order to make editable-text and onbeforesave works.

Hope this helps.

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

Comments

-1

Just add another directive inside template of first directive and bind it to scope model that you get from attr. You can also add controller function, and create more models, or logic and bind to directive template.

Also maybe your attributes may not be available on template, than you need to add $watch to your isolated scope model and update another scope model inside controller. That second one model needs to be binded to template. More information about directives you can find on AngularJS docs, but also here is one good article, it can help you:

http://www.sitepoint.com/practical-guide-angularjs-directives-part-two/

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.