2012-11-29 77 views
1

嘿我在我的燼應用程序中有兩個不同的問題,它們都涉及綁定。灰燼綁定不需要時觸發,當需要時不觸發

首先,我有一個綁定的射擊,當我不想要它。基本上我試圖達到的目標(我正在構建一個調查創建者前端應用程序)是,當任何文本輸入到問題的「名稱」字段中時,我想添加一個新的問題對象,它將呈現在用戶添加的問題列表的末尾列出另一個空白問題。這具有始終存在新問題的效果,因此不需要添加問題按鈕。綁定正在工作,並且正在添加一個新對象:但是,由於綁定來自最新的問題對象,因此綁定會在創建新對象時再次觸發,從而創建一個新對象,從而再次觸發綁定....顯然最終會導致瀏覽器崩潰。我嘗試過使用Ember._suspendObserver函數,但是沒有很多關於此的文檔,我認爲我錯誤地使用它 - 總之它不會暫停觀察者或暫停綁定。代碼中的觀察者在第27行左右(contentsNameObserver)

我遇到的另一個問題 - 我有一個選擇下拉框,它選擇用戶想要的問題類型(單個答案,多項選擇等) ),但是選擇框和{{#each}}幫助器之間的綁定會導致問題的類型不會被觸發。我使用Ember.Select視圖助手,因此使用get/set來觸發綁定應該沒有任何問題。我正在使用計算屬性根據問題類型ID的值返回問題類型的字段數組。計算出的屬性在第13行(App.SurveyContent.types)和模板模板/ step3中。很快就會發現,這個應用程序可能被擴展的不僅僅是調查,因此'問題'在代碼中經常被稱爲'內容'。我是非常新的燼(這是我的第一個真正的應用程序),所以我的代碼最有可能有這些問題之外的問題很多...所以對我如何構建我的應用程序的任何意見將是巨大的也很感激!

的Javascript應用程序的餘燼:

App = Ember.Application.create({ 
    rootElement: '#emberContainer' 
}); 

App.SurveyContent = Ember.Object.extend({ 
    name: "", 
    content_type: 1, 
    content_pos: 1, 
    hash: Em.A([]), 

    types: function() { 
    alert("redraw"); 
    return App.ContentTypes[this.content_type-1].hash; 
    }.property() 

}); 

App.Surveys = Ember.Object.create({ 
    name: null, 
    start: $.datepicker.formatDate('mm/dd/yy' , new Date()), 
    end: $.datepicker.formatDate('mm/dd/yy' , new Date()), 
    themeID: 0, 
    contents: [App.SurveyContent.create()], //Pushing an instance of App.SurveyContent onto this 

    contentsNameObserver: function() { 
    context = this; 
    console.log("entering"); 
    Em._suspendObserver(App.Surveys, "contents.lastObject.name", false, false, function() { 
     console.log("suspend handler"); 
     context.contents.pushObject(App.SurveyContent.create()); 
    }) 
    }.observes("contents.lastObject.name") 

}); 

App.ContentTypes = [ 
    Ember.Object.create({name: 'Text question', id:1, hash: [Ember.Object.create({name: 'Question', help: 'Enter the question here', type: 'text'})]}), 

    Ember.Object.create({name: 'Multichoice question', id:2, hash: [Ember.Object.create({name: 'Question', help: 'Enter the question here', type: 'text'}), 
         Ember.Object.create({name: 'Answer', help: 'Enter possible answers here', type: 'text', multiple: true})]}) 
]; 

App.ViewTypeConvention = Ember.Mixin.create({ 
    viewType: function() { 
    console.log(this); 
    return Em.get("Ember.TextField"); 
    }.property().cacheable() 
}); 


App.CRMData = Ember.Object.extend(); 

App.CRMData.reopenClass ({ 
    crm_data: [], 
    org_data: [], 
    org_display_data: [], 

    loadData: function() { 
    context = this; 
    context.crm_data = []; 
    $.getJSON ("ajax/crm_data", function(data) { 
     data.forEach(function(crm) { 
     context.crm_data.pushObject(App.CRMData.create({id: crm.crm_id, name: crm.crm_name})); 
     crm.orgs.forEach(function(org) { 
      context.org_data.pushObject(App.CRMData.create({id: org.org_id, name: org.org_name, crm_id: crm.crm_id})); 
     }, context) 
     }, context) 
     context.updateOrganisations(5); 
    }); 
    return this.crm_data; 
    }, 
    updateOrganisations: function(crm_id) { 
    context = this; 
    this.org_display_data.clear(); 
    console.log("clearing the buffer") 
    console.log(this.org_display_data) 
    context.org_data.forEach(function(org) { 
     if(org.crm_id == crm_id) { 
     context.org_display_data.pushObject(App.CRMData.create({id: org.id, name: org.name})); 
     } 
    }, context) 
    } 
}); 

App.DateField = Ember.TextField.extend({ 
    attributeBindings: ['id', 'class'] 
}); 

App.CRMSelect = Ember.Select.extend({ 
    attributeBindings: ['id'], 
    change: function(evt) { 
    console.log(evt) 
    App.CRMData.updateOrganisations($('#crm').val()) 
    } 
}); 

App.ApplicationController = Ember.Controller.extend(); 

App.Step1Controller = Ember.ArrayController.extend({}); 

App.Step2Controller = Ember.ArrayController.extend({}); 

App.Step2Controller = Ember.ArrayController.extend({}); 

App.ApplicationView = Ember.View.extend({ 
    templateName: 'app' 
}); 

App.Step0View = Ember.View.extend ({ 
    templateName: 'templates/step0' 
}); 

App.Step1View = Ember.View.extend ({ 
    templateName: 'templates/step1' 
}); 

App.Step2View = Ember.View.extend ({ 
    templateName: 'templates/step2', 
    didInsertElement: function() { 
    $(".jquery-ui-datepicker").datepicker(); 
    } 
}); 

App.Step3View = Ember.View.extend ({ 
    templateName: 'templates/step3', 
}); 



App.Router = Em.Router.extend ({ 
    enableLogging: true, 

    root: Em.Route.extend ({ 
    showstep1: Ember.Route.transitionTo('step1'), 
    showstep2: Ember.Route.transitionTo('step2'), 
    showstep3: Ember.Route.transitionTo('step3'), 

    index: Ember.Route.extend({ 
     route: '/', 
     connectOutlets: function(router){ 
     router.get('applicationController').connectOutlet('step0'); 
     }  
    }), 

    step1: Ember.Route.extend ({ 
     route: 'step1', 
     connectOutlets: function(router){ 
     router.get('applicationController').connectOutlet('step1', App.CRMData.loadData()); 
     } 
    }), 

    step2: Ember.Route.extend ({ 
     route: 'step2', 
     connectOutlets: function(router) { 
     router.get('applicationController').connectOutlet('step2') 
     }, 
    }), 

    step3: Ember.Route.extend ({ 
     route: 'step3', 
     connectOutlets: function(router) { 
     router.get('applicationController').connectOutlet('step3') 
     }, 
    }) 
    }) 
}); 


Ember.LOG_BINDINGS=true; 

App.LOG_BINDINGS = true; 

App.ContentTypes.forEach(function(object) { 
    object.hash.forEach(function(hash) { 
    hash.reopen(App.ViewTypeConvention); 
    }, this); 
}, this); 

HTML模板(我在HAML了這些,所以這是重要的的只是一種表象)

<script type="text/x-handlebars" data-template-name="app"> 
{{outlet}} 
</script> 

<script type="text/x-handlebars" data-template-name="templates/step3"> 
<h1> Add content to {{App.Surveys.name}} </h1> 
<br> 

<div id = "accordion2" class = "accordion"> 
    {{#each content in App.Surveys.contents}} 
    <div class="accordion-group"> 
    <div class = "accordion-heading"> 
     <a class = "accordion-toggle" data-parent = "#accordion2" data-toggle = "collapse" href = "#collapseOne"> 
     {{content.name}} 
     </a> 
    </div> 
    <div id = "collapseOne" class = "accordion-body collapse in"> 
     {{view Ember.TextField valueBinding="content.name" class="txtName"}} 
     <form class = "form-horizontal"> 
     <div class = "accordion-inner"> 
      <div class = "control-group"> 
      <label class = "control-label" for ="organisation"> 
       Content Type 
       <div class = "controls"> 
       {{view Ember.Select contentBinding="App.ContentTypes" optionValuePath="content.id" optionLabelPath="content.name" valueBinding="content.content_type"}} 
       </div> 
      </div> 
      </div> 
      {{#each item in content.types }} 
      <div class = "control-group" > 
      <label class = "control-label" for = "organisation"> 
       {{item.name}} 
       <div class = "controls"> 
       {{view item.viewType }} 
       </div> 
      {{/each}} 
      </div> 
     </form> 
    </div> 
    {{/each}} 
    </div> 
</div> 

<br> 

<div class = "btn" {:_action => 'showstep3'}> Next Step > </div> 
</script> 
+0

請創建jsfiddle .. – thecodejack

+0

http://jsfiddle.net/reubenposthuma/sHPv4/ –

回答

0

我已經解決了第一問題,雖然我沒有得到suspendObserver屬性的工作我用一個if語句來檢查以前的元素,刪除無限循環。

contentsNameObserver: function() { 
    context = this; 
    if(this.get('contents.lastObject').name) { 
    context.contents.pushObject(App.SurveyContent.create()); 
    } 
}.observes("contents.lastObject.name") 

如何獲得_suspendObserver處理工作任何評論都將雖然讚賞,這是應該工作,但我做錯了

我在http://jsfiddle.net/reubenposthuma/sHPv4/

創建一個精簡的jsfiddle

它設置爲直接進入問題步驟第3步,以便我不需要包含所有以前的模板。

我仍然堅持綁定問題,但沒有解僱。我期望的行爲是當「內容類型」下拉框改變時,下面的文本框應該改變,它應該用兩個文本框重新呈現。

0

我意識到這是一個古老的問題,但沒有文檔和寶貴的小信息,我可以找到搜索,因此分享我在這裏找到的工作。

我發現工作是調用Ember._suspendObserver如下:

somePropertyDidChange: function(key) { 
    var that = this; 

    Ember._suspendObserver(this, key, null, 
    'somePropertyDidChange', function() { 

    // do stuff which would normally cause feedback loops 
    that.set('some.property', 'immune to feedback'); 
    }); 
}.observes('some.property'); 

您也可以使用多個觀察員變異如下:

somePropertiesDidChange: function(key) { 
    var that = this; 
    Ember._suspendObservers(this, ['some.property', 'another.property'], 
    null, 'somePropertiesDidChange', function() { 

    // do stuff which would normally cause feedback loops 
    that.set('some.property', 'immune to feedback'); 
    that.set('another.property', 'also immune to feedback'); 
    }); 
}.observes('some.property', 'another.property'); 

在我的確切使用情況下,我實際上是從所謂的Ember._suspendObservers一個Ember.run.once()功能,這是由觀察員設置的,因爲我想確保一些相關屬性在進行計算之前已經確定了,這些計算反過來會改變這些屬性中的一些。