如何在嵌套组件中的EmberJS中处理动作

时间:2019-01-06 21:07:44

标签: javascript ember.js components action

所以我在EmberJS中嵌套了组件,无法正确处理它们的动作。

我有路线Create及其模板组件pixel-grid

<div class="row">
    <div class="col-sm-7">
        {{pixel-grid}}
    </div>
    <div class="col-sm-5">

    </div>
</div>

pixel-grid模板中,我有一个名为pixel-cell的组件:

<table class="mx-auto">
    {{#each (range 0 panelWidth) as |row|}}
    <tr class="table-row">
        {{#each (range 0 panelHeight) as |cell|}}
        <th class="table-cell">
            {{pixel-cell onClick=(action 'changeColor')}}
        </th>
        {{/each}}
    </tr>
    {{/each}}
</table>

组件pixel-cell的模板为空,因为我暂时不需要它。在pixel-cell组件js文件中,我有:

import Component from '@ember/component';
export default Component.extend({
    classNames: ['cell', 'clickable'],
    tagName: 'div',

    init() {
        this._super(...arguments);
    },
});

由于我没有处理此操作,因此该代码显然无法编译。 但是..

我试图在pixel-cell中设置动作,但是Ember告诉我pixel-grid应该具有该动作。 因此,我确实将此changeColor动作放到了pixel-grid->上不起作用。

所以我试图通过pixel-cell js中的类似方法来处理此问题:

click() {
    this.sendAction('changeColor');
},

->无效。

我不知道它应该如何工作; /我试图阅读指南,但仍然无法解决。请帮忙。

4 个答案:

答案 0 :(得分:2)

我建议不要处理对组件元素的操作。而是总是使用关闭动作!

如果您执行{{some-component onClick=(action 'changeColor')}},则需要在changeColor内相应的 not 上执行操作some-component!但是,您可能想像这样在some-component内部使用它:

<button onclick={{@changeColor}}>...</button>

在您的情况下,我将为tagName: ''组件设置pixel-cell并添加以下模板:

<div onclick={{@changeColor}}></div>

答案 1 :(得分:1)

我个人从未使用过export default Component.extend({ actions: { changeColor(cell) { console.log("CELL ACTION"); console.log(cell); cell.style.backgroundColor = 'red'; } } }); 。相反,您应该将操作作为属性从父级传递到子级组件,然后在子级组件中调用它们。这种方法以及https://emberigniter.com/send-closure-actions-up-data-owner/详尽解释的其他好处要容易得多。

在您的示例中:

pixel-grid.js:

{{pixel-cell handleColorChange=(action 'changeColor')}}

pixel-grid.hbs:

export default Component.extend({
    classNames: ['cell', 'clickable'],
    tagName: 'div',

    click: function () {
        // Invoke parent action and pass this element as the argument
        this.get("handleColorChange")(this.element);
    }
});

pixel-cell.js:

<script src="https://polyfill.io/v2/polyfill.js?features=default,es5,es6&flags=gated,always"></script>
<script src="https://unpkg.com/@babel/standalone@7.2.5/babel.js"></script>

<script type="text/babel" data-presets="es2015,es2016,es2017,stage-3">
async function test() { return 10; }  
console.log("done");
</script>

答案 2 :(得分:1)

https://ember-twiddle.com/e04e318489bcc8e9e921e849c9fb9e9e?openFiles=templates.components.pixel-cell.hbs%2Ctemplates.components.pixel-grid.hbs

我创建了一个旋转控件,向您展示了从父组件传递到子组件的示例动作。您可以参考上面的网址,以使其更容易理解。

我使用了一个叫做闭包动作的概念,而不是sendAction,这是Ember今后的规范。

答案 3 :(得分:0)

好,所以我确实设法使它起作用。看起来像这样:

pixel-grid模板:

<table class="mx-auto">
    {{#each (range 0 panelWidth) as |row|}}
    <tr class="table-row">
        {{#each (range 0 panelHeight) as |cell|}}
        <th class="table-cell">
            {{pixel-cell}}
        </th>
        {{/each}}
    </tr>
    {{/each}}
</table>

pixel-cell组件js文件:

import Component from '@ember/component';
export default Component.extend({
    classNames: ['cell', 'clickable'],
    tagName: 'div',

    click: function () {
        this.sendAction('changeColor', this);
    },

    changeColor(cell) {
        console.log("CELL ACTION");
        console.log(cell);
        cell.element.style.backgroundColor = 'red';
    }
});

其他文件为空(pixel-grid js文件中只有panelHeight和panel Width)。 这是这样做的好方法吗?