2013-01-11 18 views
10

Próbuję zintegrować piękną edytor WYSIWYG (http://imperavi.com/redactor/) w niestandardowej dyrektywie AngularJS.Integracja Redactor WYSIWYG w dyrektywie AngularJs

visualy to działa, ale moja dyrektywa zwyczaj nie jest kompatybilny z NG-modelu (i nie rozumiem dlaczego)

W ten sposób można korzystać z dyrektywy:

<wysiwyg ng-model="edited.comment" id="contactEditCom" content="{{content}}" required></wysiwyg> 

I jest to kod dyrektywa:

var myApp = angular.module('myApp', []); 
myApp.directive("wysiwyg", function(){ 

var linkFn = function(scope, el, attr, ngModel) { 

    scope.redactor = null; 

    scope.$watch('content', function(val) { 
     if (val !== "") 
     { 
      scope.redactor = $("#" + attr.id).redactor({ 
       focus : false, 
       callback: function(o) { 
        o.setCode(val); 
        $("#" + attr.id).keydown(function(){ 
         scope.$apply(read); 
        }); 
       } 
      }); 
     } 
    }); 

    function read() { 
     var content = scope.redactor.getCode(); 
     console.log(content); 
     if (ngModel.viewValue != content) 
     { 
      ngModel.$setViewValue(content); 
      console.log(ngModel); 
     } 
    } 

}; 

return { 
    require: 'ngModel', 
    link: linkFn, 
    restrict: 'E', 
    scope: { 
     content: '@' 
    }, 
    transclude: true 
}; 
}); 

I wreszcie jest to skrzypce ->http://fiddle.jshell.net/MyBoon/STLW5/

+0

W read(), ngModel.viewValue powinny być ngModel $ viewValue.. Co rozumiesz przez "moja dyrektywa nie jest zgodna z modelem ng"? –

+0

Chcę tylko, aby moja dyrektywa niestandardowa działała jak inne wejścia. Na przykład, gdy to napiszesz: zmienna zasięgu "edited.input" zostanie wypełniona, jeśli tekst jest wpisany. Staram się zachować takie samo zachowanie w mojej dyrektywie. – MyBoon

Odpowiedz

4

zrobiłem jeden na podstawie dyrektywy TinyMCE kątowej-ui w. Ten słucha również formatowania kliknięć przycisków. Zajmuje się także przypadkiem, gdy model jest zmieniany poza dyrektywą.

directive.coffee (żal coffeescript)

angular.module("ui.directives").directive "uiRedactor", ["ui.config", (uiConfig) -> 

    require: "ngModel" 
    link: (scope, elm, attrs, ngModelCtrl) -> 
    redactor = null 

    getVal = -> redactor?.getCode() 

    apply = -> 
     ngModelCtrl.$pristine = false 
     scope.$apply() 

    options = 
     execCommandCallback: apply 
     keydownCallback: apply 
     keyupCallback: apply 

    scope.$watch getVal, (newVal) -> 
     ngModelCtrl.$setViewValue newVal unless ngModelCtrl.$pristine 


    #watch external model change 
    ngModelCtrl.$render = -> 
     redactor?.setCode(ngModelCtrl.$viewValue or '') 

    expression = if attrs.uiRedactor then scope.$eval(attrs.uiRedactor) else {} 

    angular.extend options, expression 

    setTimeout -> 
     redactor = elm.redactor options 
] 

HTML

<textarea ui-redactor='{minHeight: 500}' ng-model='content'></textarea> 
+0

@MichaelCalkins, czy ten skrypt nadal istnieje? To nie jest w połączonej lokalizacji. –

+0

@RhysvanderWaerden Wystarczy google wokół lub spróbuj https://github.com/TylerGarlick/angular-redactor –

1

Sprawdź, czy to jest ta fiddle.

NG-model może być ustawiony do treści:

<wysiwyg ng-model="content" required></wysiwyg> 

Wewnątrz funkcji wiążącej, el jest już ustawiony do elementu, w którym dyrektywa jest zdefiniowany, więc id nie jest potrzebne. I el jest już zapakowanym elementem jQuery.

funkcja Link:

var linkFn = function (scope, el, attr, ngModel) { 
    scope.redactor = el.redactor({ 
     focus: false, 
     callback: function (o) { 
      o.setCode(scope.content); 
      el.keydown(function() { 
       console.log(o.getCode()); 
       scope.$apply(ngModel.$setViewValue(o.getCode())); 
+0

Heads up nie czyni tego elementem, ponieważ zakłóca działanie css dla redaktora. Ustaw ograniczenie atrybutów: "A", –

1

Proponowane rozwiązanie jest

1) klon https://github.com/dybskiy/redactor-js.git 2) obejmują jQuery redactor.js, redaktor, .css 3) dodaj tag: <textarea wysiwyg ng-model="post.content" cols="18" required></textarea> do korpusu html 4) dodaj dyrektywę:

yourapp.directive('wysiwyg', function() { 
    return { 
    require: 'ngModel', 
    link: function (scope, el, attrs, ngModel) { 
     el.redactor({ 
     keyupCallback: function(obj, e) { 
      scope.$apply(ngModel.$setViewValue(obj.getCode())); 
     } 
     }); 
     el.setCode(scope.content); 
    } 
    }; 
}); 

poważaniem, Jeliuc Alexandr

4

AKTUALIZACJA --- Rails 4.2 --- skośnych Rails 1.3.14

Alright guys, po wielu badaniach i jakąś pomoc ze strony innych członków na przepełnienie stosu o to rozwiązanie, które karmi prosto do zakresu kontroler dolarów i do NG-modelu stosuje się do pola tekstowego:

** Render Raw HTML **

# Filter for raw HTML 
app.filter "unsafe", ['$sce', ($sce) -> 
    (htmlCode) -> 
     $sce.trustAsHtml htmlCode 
] 

Credit for Filter

dyrektywa:

# For Redactor WYSIWYG 
app.directive "redactor", -> 
require: "?ngModel" 
link: ($scope, elem, attrs, controller) -> 
    controller.$render = -> 
     elem.redactor 
      changeCallback: (value) -> 
       $scope.$apply controller.$setViewValue value 
      buttons: ['html', '|', 'formatting', '|', 
       'fontcolor', 'backcolor', '|', 'image', 'video', '|', 
       'alignleft', 'aligncenter', 'alignright', 'justify', '|', 
       'bold', 'italic', 'deleted', 'underline', '|', 
       'unorderedlist', 'orderedlist', 'outdent', 'indent', '|', 
       'table', 'link', 'horizontalrule', '|'] 
      imageUpload: '/modules/imageUpload' 
     elem.redactor 'insert.set', controller.$viewValue 

Last line update reason

w widoku HTML:

<div ng-controller="PostCtrl"> 
    <form ng-submit="addPost()"> 
     <textarea ng-model="newPost.content" redactor required></textarea> 
     <br /> 
     <input type="submit" value="add post"> 
    </form> 

    {{newPost.content}} <!-- This outputs the raw html with tags --> 
    <br /> 
    <div ng-bind-html="newPost.content | unsafe"></div> <!-- This outputs the html --> 
</div> 

a kontrolerem:

$scope.addPost = ->  
    post = Post.save($scope.newPost) 
    console.log post 
    $scope.posts.unshift post 
    $scope.newPost.content = "<p>Add a new post...</p>" 

aby zapobiec TypeError z redaktor zapełnić wartość do pola tekstowego przed wywołaniem akcji, to najlepiej pracował dla mnie, aby zachować formatowanie:

# Set the values of Reactor to prevent error 
    $scope.newPost = {content: '<p>Add a new post...</p>'} 

Jeśli jesteś na bieg do błędów CSRF będzie to rozwiązać ten problem:

# Fixes CSRF Error OR: https://github.com/xrd/ng-rails-csrf 
app.config ["$httpProvider", (provider) -> 
    provider.defaults.headers.common['X-CSRF-Token'] = angular.element('meta[name=csrf-token]').attr('content') 

]

Much dzięki: AngularJS & Redactor Plugin

Wreszcie ....

Jeśli używasz powtórzenia polecenia ng do utworzenia tych obszarów tekstu korekcji i masz problemy z dostępem do zakresu, sprawdź tę odpowiedź: Accessing the model inside a ng-repeat

+1

Teraz możesz użyć nowego "changeCallback". "execCommandCallback" nie jest już używany. Zobacz: changeCallback: funkcja (html) {} – benske

+0

zaktualizowana dla nowego interfejsu API – blnc

1

Powyższe rozwiązania nie sprawdziły się we wszystkich sytuacjach, więc użyłem ich do utwórz następującą dyrektywę, która zachowuje synchronizację modelu i redaktora.

angular.module('redactor', []) 

.directive (funkcja 'redaktor'() { powrotu { wymagające:, ngModel łącza '?': Funkcyjne (zakres, EL, attrs, ngModel) {

// Function to update model 
    var updateModel = function() { 
     scope.$apply(ngModel.$setViewValue(el.getCode())); 
    }; 

    // Get the redactor element and call update model 
    el.redactor({ 
    keyupCallback: updateModel, 
    keydownCallback: updateModel, 
    execCommandCallback: updateModel, 
    autosaveCallback: updateModel 
    }); 

    // Call to sync the redactor content 
      ngModel.$render = function(value) { 
     el.setCode(ngModel.$viewValue); 
    }; 
    } 
}; 

});

Wystarczy dodać moduł redaktor jako zależność i dodaje do kodu HTML:

Uwaga: musiałem zaktualizować kod po aktualizacji do wersji 9.1.1

Oto nowa wersja:

.directive('redactor', function() { 
     return { 
      require: '?ngModel', 
      link: function (scope, el, attrs, ngModel) { 

      var updateModel, errorHandling; 
      // Function to update model 
      updateModel = function() { 
       if(!scope.$$phase) { 
        scope.$apply(ngModel.$setViewValue(el.redactor('get'))); 
       } 
       }; 

      uploadErrorHandling = function(response) 
       { 
       console.log(response.error); 
       alert("Error: "+ response.error); 
       }; 

      // Get the redactor element and call update model 
      el.redactor({ 
       minHeight: 100, 
       buttons: ['formatting', '|', 'bold', 'italic', 'deleted', '|', 
       'unorderedlist', 'orderedlist', 'outdent', 'indent', '|', 
       'image', 'video', 'file', 'table', 'link', '|', 'alignment', '|', 'horizontalrule'], 
       keyupCallback: updateModel, 
       keydownCallback: updateModel, 
       changeCallback: updateModel, 
       execCommandCallback: updateModel, 
       autosaveCallback: updateModel, 
       imageUpload: '/file/upload/image', 
       imageUploadErrorCallback: uploadErrorHandling, 
       imageGetJson: '/api/v1/gallery' 
       }); 

      // Call to sync the redactor content 
       ngModel.$render = function(value) { 
        el.redactor('set', ngModel.$viewValue); 
       }; 
      } 
     }; 
     }); 
Powiązane problemy