简体   繁体   English

如何在Ember视图中同步有状态控件?

[英]How do you synchronise stateful controls in an Ember view?

I have a basic Ember application. 我有一个基本的Ember应用程序。 It has 2 controls: a select element and a text field. 它有2个控件:一个选择元素和一个文本字段。 The controls are used to change what data is visible. 控件用于更改可见的数据。 Using the select element you can choose to see all numbers, even numbers only, or odd numbers only. 使用select元素,您可以选择查看所有数字,仅查看数字,或仅查看奇数。 Using the text field you can search for numbers that contain the digits you input. 使用文本字段,您可以搜索包含您输入的数字的数字。

I want the controls need to behave indepentently. 我希望控件需要独立运行。 By that I mean that if I type into the text field after choosing an option from the select element, the select element should be reset. 我的意思是,如果我在从select元素中选择一个选项后输入文本字段,则应该重置select元素。 Likewise if I choose an option from the select element, the text field should be cleared. 同样,如果我从select元素中选择一个选项,则应清除文本字段。

I find this difficult to implement because if I call this.set('query', '') in select 's observer, I will trigger the query 's observer which is programmed to set content to all the numbers when query === '' . 我发现这很难实现,因为如果我在select的观察者中调用this.set('query', '') ,我将触发query的观察者,该观察者被编程为在query === ''时将content设置为所有数字query === '' In other words, this approach makes it so that choosing even numbers will cause the text field to clear which will cause all the numbers to be visible which is wrong since even numbers were chosen! 换句话说,这种方法使得选择偶数将导致文本字段清除,这将导致所有数字都可见,这是错误的,因为选择了偶数!

The way I got it to work way by putting a check for the value of select in the query_changed method. 我通过在query_changed方法中检查select值来query_changed方式。 This feels like a bad solution. 这感觉就像一个糟糕的解决方案 I imagine that if there were many more than 2 controls, this approach would fill up observers with many if statements. 我想如果有超过2个控件,这种方法会用很多if语句填充观察者。

query_changed: function() {
    var query = this.get('query');
    if (query === '') {
        if (this.get('select').value === '') {  // <-- is there a better way?
            this.set('content', this.get('numbers'));
        }
    } else {
        var output = $.map(this.get('numbers'), function(number, i) {
            if (_.string.include(number, query)) {
                return number;
            }
            return null;
        });
        this.set('content', output);
    }
}.observes('query')

I tried a few other ideas, but they were all basically like the above. 我尝试了其他一些想法,但它们基本上都像上面那样。

How are you supposed to handle this in Ember? 你怎么在Ember处理这件事? I looked at Ember.StateManager and it looks like it is meant to handle multiple views. 我查看了Ember.StateManager ,看起来它意味着处理多个视图。 Here I have only one view with stateful controls. 这里我只有一个有状态控件的视图。

Demo: http://jsfiddle.net/DxbeB/1/ 演示: http//jsfiddle.net/DxbeB/1/

The code without anything to synchronize the controls: 没有任何东西来同步控件的代码:

App = Ember.Application.create({});
App.controller = Ember.Object.create({
    numbers: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
    contentBinding: Ember.Binding.oneWay('numbers'),
    select: null,
    query: null,
    select_changed: function() {
        if (this.get('select').value === 'all') {
            this.set('content', this.get('numbers'));
        }
        if (this.get('select').value === 'even') {
            var output = $.map(this.get('numbers'), function(number, i) {
                if (number % 2 === 0) {
                    return number;
                }
                return null;
            });
            this.set('content', output);
        }
        if (this.get('select').value === 'odd') {
            var output = $.map(this.get('numbers'), function(number, i) {
                if (number % 2 !== 0) {
                    return number;
                }
                return null;
            });
            this.set('content', output);
        }

    }.observes('select'),
    query_changed: function() {
        var query = this.get('query');
        if (query === '') {
            this.set('content', this.get('numbers'));
        } else {
            var output = $.map(this.get('numbers'), function(number, i) {
                if (_.string.include(number, query)) {
                    return number;
                }
                return null;
            });
            this.set('content', output);
        }
    }.observes('query')
});

App.Select = Ember.Select.extend({
    content: [{label: '', value: ''}, {label: 'All numbers', value: 'all'}, {label: 'Even numbers', value: 'even'}, {label: 'Odd numbers', value: 'odd'}],
    optionLabelPath: 'content.label',
    optionValuePath: 'content.value'
});

App.MyView = Ember.View.extend({
    controllerBinding: 'App.controller'
});

The template: 模板:

{{#view App.MyView}}
    {{view App.Select selectionBinding="controller.select"}}
    {{view Ember.TextField valueBinding="controller.query"}}
    <p>{{controller.content}}</p>
{{/view}}

You could observe when the odd/even filter value is set on the controller and then reset the query value and vice versa, see http://jsfiddle.net/pangratz666/bWT4E/ : 您可以观察何时在控制器上设置odd/even filter值然后重置query值,反之亦然,请参阅http://jsfiddle.net/pangratz666/bWT4E/

Handlebars : 把手

<script type="text/x-handlebars" >
    {{#view App.MyView}}
        {{view App.Select selectionBinding="select"}}
        {{view Ember.TextField valueBinding="query"}}
        <hr/>
        {{#each controller.filtered}}
            {{this}}
        {{/each}}   
    {{/view}}
</script>​

JavaScript : JavaScript

App = Ember.Application.create({
    oddFilter: function(value) {
        return value % 2 === 1;
    },
    evenFilter: function(value) {
        return value % 2 === 0;
    },
    queryFilter: function(query) {
        return function(value) {
            return (value + '').indexOf(query) !== -1;
        };
    }
});

App.Select = Ember.Select.extend({
    prompt: 'define filter',
    content: ['odd', 'even']
});

App.controller = Ember.ArrayProxy.create({
    content: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30],

    _queryChanged: function() {
        var q = this.get('query');
        if (!Ember.empty(q)) {
            this.set('select', null);
        }
    }.observes('query'),

    _selectChanged: function() {
        var s = this.get('select');
        if (!Ember.none(s)) {
            this.set('query', null);
        }
    }.observes('select'),

    filtered: function() {
        var s = this.get('select');
        var q = this.get('query');
        var filter = Ember.K;
        if (s === 'odd') {
            filter = App.get('oddFilter');
        } else if (s === 'even') {
            filter = App.get('evenFilter');
        } else if (!Ember.empty(q)) {
            filter = App.get('queryFilter')(q);
        }

        return this.filter(filter, this);
    }.property('select', 'query').cacheable()
});

App.MyView = Ember.View.extend({
    controllerBinding: 'App.controller',
    selectBinding: 'controller.select',
    queryBinding: 'controller.query'
});​

Regarding your question if (this.get('select').value === '') { // <-- is there a better way? 关于你的问题if (this.get('select').value === '') { // <-- is there a better way? : Always access properties via set and get . :始终通过setget访问属性。 This assures that the Binding stuff in Ember works as expected. 这确保了Ember中的Binding内容按预期工作。 Also, there are some utilities functions, so checking for an empty string can be done via Ember.empty(value) . 此外,还有一些实用程序函数,因此可以通过Ember.empty(value)来检查空字符串。 See a blog post about that: http://code418.com/blog/2012/03/08/useful-emberjs-functions/ 请参阅博客文章: http//code418.com/blog/2012/03/08/useful-emberjs-functions/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM