2015-03-03 62 views
0

我有这样的代码,我需要用的CKEditor连接:Knockoutjs + CKEDITOR需要帮助您计算出来的东西

基本上我试图做的是把它与数据绑定的是已经存在通过连接:

textarea autocomplete="off" class="form-control" data-bind="rev_ckeditor, value: app.models.userReview.body" id="editor" maxlength="50000" name="body" cols="50" rows="10"

上面的textarea同时具有值​​data-bind和ckeditor的data-dind。但是ckwditor显示出来了,但不是数值绑定的值,是不是有什么问题?

代码:

(function($) { 
'use strict' 

app.viewModels.reviews = { 

    /** 
    * All reviews. 
    * 
    * @type ko.observable(Array) 
    */ 
    sourceItems: ko.observableArray([]), 

    /** 
    * Sorting type and order. 
    * 
    * @type ko.observable(String) 
    */ 
    currentSort: ko.observable(), 

    /** 
    * Holds average score of all critic reviews. 
    * 
    * @type ko.observable(String) 
    */ 
    criticAverage: ko.observable(), 

    /** 
    * Holds count of all critic reviews. 
    * 
    * @type ko.observable(String) 
    */ 
    criticCount: ko.observable(), 

    /** 
    * Holds average score of all user reviews. 
    * 
    * @type ko.observable(String) 
    */ 
    userAverage: ko.observable(), 

    /** 
    * Holds count of all user reviews. 
    * 
    * @type ko.observable(String) 
    */ 
    userCount: ko.observable(), 

    /** 
    * Whether to who user, critic or all reviews. 
    * 
    * @type ko.observable(String) 
    */ 
    currentType: ko.observable(), 

    /** 
    * Send request to server to create a new 
    * user review. 
    * 
    * @return void 
    */ 
    create: function(form) { 
     var self = this; 

     var params = { 
      data: ko.toJSON(app.models.userReview), 
      success: function(response) { 
       var exists = false; 

       $.each(self.sourceItems(), function(i,v) { 

        //if user has already written a review for this game we'll just replace 
        //it with this one as that's what backend is doing as well 
        if (v.type == 'user' && v.user_id == parseInt(vars.userId)) { 

         self.sourceItems()[i] = ko.toJS(app.models.userReview); 
         self.sourceItems.notifySubscribers(); 
         exists = true; 
         return false; 
        } 
       }); 

       if (! exists) { 
        self.sourceItems.push(ko.toJS(app.models.userReview)); 
       } 

       $('#review-modal').modal('hide'); 
       app.utils.noty(response, 'success'); 
      }, 

      /** 
      * Append any validation errors returned to new review form. 
      * 
      * @param jq 
      * @return void 
      */ 
      error: function(jq) { 
       $('.alert').remove(); 
       app.utils.appendError(jq); 
      }, 
      url: form.action, 
     }; 

     app.utils.ajax(params); 
    }, 

    /** 
    * Handle user click on review edit button. 
    * 
    * @param app.models.review review 
    * @return void 
    */ 
    edit: function(review) { 
     app.models.userReview.id(review.id); 
     app.models.userReview.title(review.title); 
     app.models.userReview.body(review.body); 
     app.models.userReview.score(review.score); 
     app.models.userReview.story_rev(review.story_rev); 
     app.models.userReview.animation_rev(review.animation_rev); 
     app.models.userReview.sound_rev(review.sound_rev); 
     app.models.userReview.characters_rev(review.characters_rev); 
     app.models.userReview.enjoyment_rev(review.enjoyment_rev); 

     $('#review-modal').modal('show'); 
    }, 

    /** 
    * Handle user click on delete button. 
    * 
    * @param Object review 
    * @return void 
    */ 
    delete: function(review) { 
     var self = app.viewModels.reviews; 

     app.utils.ajax({ 
      url: vars.urls.baseUrl+'/movies/'+vars.titleId+'/reviews/'+review.id, 
      type: 'DELETE', 
      data: ko.toJSON(vars.token), 
      success: function() { 
       self.sourceItems.remove(review); 
      } 
     }) 
    } 
}; 

/** 
* Calculate average critic/user review score as well as review counts. 
* 
* @return void 
*/ 
app.viewModels.reviews.calculateMeta = ko.computed(function() { 
    var self  = this, score = 0, 
     crCount = 0, crAvg = 0, 
     uCount = 0, uAvg = 0; 

    $.each(self.sourceItems(), function(ind, val) { 
     if (val.type == 'critic') { 
      crCount++; 
      crAvg += parseFloat(val.score); 
     } else if (val.type == 'user') { 
      uCount++; 
      uAvg += parseFloat(val.score); 
     } 
    }); 

    //set average to flash if there's no reviews otherwise calculate an avarage 
    crCount ? self.criticAverage(crAvg/crCount) : self.criticAverage('/'); 
    uCount ? self.userAverage(uAvg/uCount) : self.userAverage('/'); 

    self.userCount(uCount); 
    self.criticCount(crCount); 

}, app.viewModels.reviews, {deferEvaluation: true}); 

/** 
* Filters critic reviews on platform dropdown change, 
* if no reviews found fires an ajax request to query 
* review data provider. 
* 
* @return array 
*/ 
app.viewModels.reviews.filteredReviews = ko.computed(function() { 
    var self = this, filtered; 

    //filter by user or critic reviews if user select either 
    if (self.currentType() === 'all') { 
     filtered = self.sourceItems(); 
    } else { 
     filtered = ko.utils.arrayFilter(self.sourceItems(), function(rev) { 
      return rev.type === self.currentType(); 
     }); 
    } 

    //split current sort by camelCase into type and order params 
    var sort = self.currentSort().match(/([A-Z]?[^A-Z]*)/g).slice(0,-1); 

    if (sort.length === 2) { 
     filtered.sort(app.utils.sort[sort[0]](sort[1])); 
    } 

    return filtered ? filtered : []; 

}, app.viewModels.reviews, {deferEvaluation: true}); 

/** 
* New review form model. 
* 
* @type Object 
*/ 
app.models.userReview = { 
    id: ko.observable(), 
    author: app.username, 
    title: ko.observable(), 
    source: 'Test', 
    body: ko.observable(), 
    story_rev: ko.observable(), 
    animation_rev: ko.observable(), 
    characters_rev: ko.observable(), 
    sound_rev: ko.observable(), 
    enjoyment_rev: ko.observable(), 
    score: ko.observable(), 
    type: 'user', 
    _token: vars.token, 
    user_id: app.user_id, 
}; 


/** 
* Renders CKeditor on textarea. 
* 
* @type {Object} 
*/ 
ko.bindingHandlers.rev_ckeditor = { 
     init: function (element, valueAccessor, allBindingsAccessor, context, review) { 
       var $element = $(element); 
       var value = ko.utils.unwrapObservable(valueAccessor()); 

       $element.html(value); 
       var editor = CKEDITOR.replace('editor'); 

       /** 
       * Resize CKeditor according to textarea col and rows attributes. 
       * 
       * @return void 
       */ 
       jQuery.fn.cke_resize = function() { 
        return this.each(function() { 
          var $this = $(this); 
          var rows = $this.attr('rows'); 
          var height = rows * 20; 
          $this.next("div.cke").find(".cke_contents").css("height", height); 
        }); 
       }; 

       CKEDITOR.on('instanceReady', function(){ $element.cke_resize(); }); 

       //Update body observable on ckeditor blur event 
       editor.on('blur', function (e) { 

         var obs = app.models.userReview.body(review.body); 

         if (ko.isWriteableObservable(obs)) { 
           obs(e.editor.getData()); 
         } 
       }); 
     } 
}; 

})(jQuery); 
+0

你能在小提琴重现? – firstdoit 2015-03-03 10:23:14

回答

1

我不熟悉的CKEditor,所以我可能是错在这里,但很多WYSIWYG编辑器不更新自己只是因为你改变了数据在基础<textarea>,这是什么你的value绑定会做。我建议完全删除value绑定,并让编辑器绑定到所有的工作。

现在,您的绑定似乎只能处理可编辑的文字编辑器更改。我们还需要处理相反的方向,并向编辑写入可观察的更改。根据该文件的CKEditor,即通过Editor#setData完成:

ko.bindingHandlers.rev_ckeditor = { 
    init: function (element, valueAccessor, allBindingsAccessor, context, review) { 
     var $element = $(element), 
      observable = valueAccessor(); 

     var editor = CKEDITOR.replace('editor'); 

     ko.computed(function() { 
      editor.setData(observable()); 
     }, { disposeWhenNodeIsRemoved: element }); 

     jQuery.fn.cke_resize = function() { 
      return this.each(function() { 
       var $this = $(this); 
       var rows = $this.attr('rows'); 
       var height = rows * 20; 
       $this.next("div.cke").find(".cke_contents").css("height", height); 
      }); 
     }; 

     CKEDITOR.on('instanceReady', function() { 
      $element.cke_resize(); 
     }); 

     editor.on('blur', function (e) { 
      if (ko.isWriteableObservable(observable)) { 
       observable(e.editor.getData()); 
      } 
     }); 
    } 
}; 

通常情况下,一个会写更改观察到的返回编辑器的绑定update处理程序。在这种情况下,在init处理程序中执行它会更方便,因为我们已经可以访问该处的编辑器实例。

如果你给编辑器结合进入观察到,一切都应该按预期工作:

<textarea data-bind="rev_ckeditor: app.models.userReview.body"></textarea> 
+0

ckeditor现在能够获取数据,但不会更新。 – Terrabyte 2015-03-03 12:51:46

+0

@Terrabyte你是如何使用编辑器绑定的?你必须授予它对observable的访问权限,就像'rev_ckeditor:app.models.userReview.body' – janfoeh 2015-03-03 12:55:58

+0

那就是我所做的,它能够获取绑定中的数据,但是当我发布新数据时,它不会更新。 – Terrabyte 2015-03-03 12:59:43