1

こんにちは、ember アプリで 2 つの異なる問題が発生しています。どちらもバインディングに関係しています。

まず、したくないときにバインディングを起動します。基本的に私が達成しようとしているのは (私は調査作成者のフロントエンド アプリを構築しています)、質問の「名前」フィールドにテキストが入力されたときに、レンダリングする新しい質問オブジェクトを追加したいということです。ユーザーが追加している質問のリストの最後に別の空白の質問を追加します。これには常に新しい質問があるという効果があるため、質問の追加ボタンは必要ありません。バインディングは機能しており、新しいオブジェクトが追加されています。ただし、バインディングは最新の質問オブジェクトからのものであるため、新しいオブジェクトが作成されるとバインディングが再びトリガーされ、新しいオブジェクトが作成され、バインディングが再びトリガーされます。 ....明らかに最終的にブラウザがクラッシュします。Ember._suspendObserver 関数を使用してみましたが、ありません。これに関する多くのドキュメントがありますが、私はそれを間違って使用していると思います-とにかく、オブザーバーを一時停止したり、バインディングを一時停止したりしていません. コード内のオブザーバーは 27 行目あたり (contentsNameObserver) です。

私が抱えているもう1つの問題-ユーザーが希望する質問のタイプ(単一回答、複数選択など)を選択する選択ドロップダウンボックスがありますが、選択ボックスと{{#each}の間のバインディング種類の質問をレンダリングするヘルパーがトリガーされません。私は Ember.Select ビュー ヘルパーを使用しているので、get/set を使用してバインディングを起動しても問題はありません。計算されたプロパティを使用して、質問タイプ ID の値に基づいて質問タイプのフィールドの配列を返しています。計算されたプロパティは 13 行目 (App.SurveyContent.types)、およびテンプレート templates/step3 にあります。このアプリは調査以外にも拡張される可能性があるため、「質問」はコード内で「コンテンツ」と呼ばれることが多いことに注意してください。

私は ember にかなり慣れていないので (これは私の最初の実際のアプリです)、私のコードにはこれらの問題以外にも多くの問題がある可能性が高いです.

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>
4

2 に答える 2

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/reubenpostthuma/sHPv4/で、簡素化された jsfiddle を作成しました。

問題のステップであるステップ 3 に直接進むように設定されているため、以前のテンプレートをすべて含める必要はありません。

私はまだバインディングが起動しないという問題に固執しています。私が期待している動作は、「コンテンツ タイプ」ドロップダウン ボックスが変更されると、その下のテキスト ボックスが変更され、2 つのテキスト ボックスで再レンダリングされることです。

于 2012-12-02T09:03:46.927 に答える
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()。これは、計算を行う前に、いくつかの依存プロパティが解決されていることを確認したかったためです。これにより、それらのプロパティの一部が変更されます。

于 2014-05-28T09:09:56.023 に答える