2

So I am working on a new site in AngularJS, and loving it!

I have encountered a problem, however. I am trying to add a jQuery plugin called 'Redactor' to my textareas, but I think what is happening is when I initialise the plugin, it replaces the textarea element. The reason this is problematic, is because I have set an 'ng-model' attribute to the text area, like so:

I am using AngularJS UI to pickup the focus event, and then execute the following code upon focus of the text

    $scope.addRedactor = function() {
        $('.redactor').redactor();
    });

Now I can't seem to get the value of the textarea, because when I try and access the ng-model 'response', it comes up as undefined.

Is there a way I can bind an ng-model attribute to the textarea AFTER it has been affected by Redactor? Else, is there another way I should be getting the textarea's value?

Sneaksta
  • 1,041
  • 4
  • 24
  • 46

3 Answers3

9

I was looking for the same answer today and made a directive to solve it:

angular.module('Module', []).directive("redactor", function() {
  return {
    require: '?ngModel',
    link: function($scope, elem, attrs, controller) {   

      controller.$render = function() {

        elem.redactor({
          keyupCallback: function() {
            $scope.$apply(controller.$setViewValue(elem.getCode()));
          },
          execCommandCallback: function() {
            $scope.$apply(controller.$setViewValue(elem.getCode()));
          }
        });

        elem.setCode(controller.$viewValue);
      };
    }
  };
});

Then you can just use the following HTML:

<textarea ng-model="yourModel" redactor></textarea>

The model will be updated on each keyUp and whenever the user clicks on a button in the toolbar. The model will contain the HTML code.

I have just started out with AngularJS so please let me know if there are better ways to do this or if I broke some conventions I am still unaware of.

BrechtVds
  • 553
  • 4
  • 7
  • I ended up using the same solution. I will mark your answer as correct so that others can see a resolution. Thanks! – Sneaksta Apr 28 '13 at 23:34
  • BTW, for those wondering how to output the model as parsed HTML:
    instead of {{yourModel}}
    – BrechtVds Apr 29 '13 at 07:10
  • I am getting a TypeError: Cannot call method 'replace' of undefined once I call in redactor due to its html content being empty. Is there a better work around than to give it a value in the controller? – blnc May 07 '13 at 06:47
  • Getting the same TypeError. Why exactly is causing this error? – Maarten May 10 '13 at 10:00
7

For those who find the accepted answer not working as I did. This is the working one (with Angular v1.1.5)

angular.module('Module', []).directive("redactor", function() {
        return {
            require: '?ngModel',
            link: function($scope, elem, attrs, controller) {
                controller.$render = function() {
                    elem = $(elem);
                    elem.val(controller.$viewValue);
                    elem.redactor({

                        changeCallback: function() {
                            $scope.$apply(controller.$setViewValue(elem.val()));
                        }

                    });

                };
            }
        };
    });

The changeCallback is way too much better than other callbacks combined and in my case, I have to cast the elem to a Jquery element. I also found that the setCode and getCode is not available at all. May be it is a different version.

David Lin
  • 13,168
  • 5
  • 46
  • 46
  • Hey David! I'm actually still working on my Redactor implementation, and just recently updated to the new version. You are correct, getCode and setCode don't exist anymore. What you can do now is simply use 'this.get()' or 'this.set()' within Redactor. – Sneaksta Jul 30 '13 at 06:00
  • Yep, API has changed. I've also noticed that the `changeCallback` seems to get called before the element receives the value and hence would always lag one character behind when doing `elem.val()`. To fix this, simply do `elem.redactor('sync')` before reading `elem.val()`. – Alen Mujezinovic Aug 08 '13 at 13:36
  • this is perfect thank you so much. Its actually working with two way binding. – Subtubes Sep 24 '13 at 02:51
  • @EdgarMartinez Would you care to share your directive? – Michael J. Calkins Dec 09 '13 at 03:54
  • 1
    I can't seem to set the value of the element after initialization. – Michael J. Calkins Dec 09 '13 at 04:01
4

Use this AngularJS module for "RedactorJS": https://github.com/TylerGarlick/angular-redactor

It worked fine for me.

benske
  • 3,922
  • 4
  • 24
  • 22
  • Were you able to use ng-model? I tried but ng-model binding are not working unless user clicks on "code" button in redactor js – Ben W Aug 27 '14 at 20:36
  • I used directevive mentioned at https://github.com/TylerGarlick/angular-redactor/issues/15 for binding to work. – Ben W Aug 27 '14 at 20:40