【问题标题】:How do you synchronise stateful controls in an Ember view?如何在 Ember 视图中同步有状态控件?
【发布时间】:2012-05-04 05:33:51
【问题描述】:

我有一个基本的 Ember 应用程序。它有 2 个控件:一个选择元素和一个文本字段。这些控件用于更改可见的数据。使用选择元素,您可以选择查看所有数字、仅查看偶数或仅查看奇数。使用文本字段,您可以搜索包含您输入的数字的数字。

我希望控件需要独立运行。我的意思是,如果我在从 select 元素中选择一个选项后输入文本字段,则应该重置 select 元素。同样,如果我从 select 元素中选择一个选项,则应清除文本字段。

我发现这很难实现,因为如果我在select 的观察者中调用this.set('query', ''),我将触发query 的观察者,该观察者被编程为在query === '' 时将content 设置为所有数字.换句话说,这种方法使得选择偶数会导致文本字段被清除,这将导致所有数字都可见,这是错误,因为选择了偶数!

我通过在query_changed 方法中检查select 的值来实现它。这感觉像是一个糟糕的解决方案。我想如果有超过 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')

我尝试了其他一些想法,但它们基本上都像上面的那样。

你应该如何在 Ember 中处理这个问题?我查看了Ember.StateManager,看起来它是用来处理多个视图的。这里我只有一个带有状态控件的视图。

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

没有任何同步控件的代码:

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'
});

模板:

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

【问题讨论】:

    标签: ember.js


    【解决方案1】:

    您可以观察何时在控制器上设置了odd/even filter 值,然后重置query 值,反之亦然,请参阅http://jsfiddle.net/pangratz666/bWT4E/

    车把

    <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

    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'
    });​
    

    关于您的问题if (this.get('select').value === '') { // &lt;-- is there a better way?:始终通过setget 访问属性。这确保了 Ember 中的 Binding 内容按预期工作。此外,还有一些实用功能,因此可以通过Ember.empty(value) 来检查空字符串。请参阅有关此的博客文章:http://code418.com/blog/2012/03/08/useful-emberjs-functions/

    【讨论】:

    • if (this.get('select').value === '') { // &lt;-- is there a better way? 的情况下,我不能使用get() 来获取值,因为选择元素的内容被定义为[{label: '', value: ''}, {label: 'All numbers', value: 'all'}, {label: 'Even numbers', value: 'even'}, {label: 'Odd numbers', value: 'odd'}]。尝试这样做会抛出TypeError: Object #&lt;Object&gt; has no method 'get'。如果我想让标签与值不同,我应该如何定义它?
    • 那是因为content 数组中的对象不是Ember.Objects。您可以改用this.getPath('select.value')。我在暗示“总是使用 getter/setter”,因为你应该总是访问这样的属性。我的例子很糟糕。很抱歉造成混乱。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多