2016-12-22 212 views
1

我想弄清楚如何在Aurelia制作Flash消息。我创建了一个自定义元素flash-message,并要求它在app.html中,但消息不会更新。如果将其设置为默认值,它会正确显示。如何在Aurelia中设置Flash消息?

app.html

<template> 
    <require from="./resources/elements/flash-message"></require> 
    <flash-message></flash-message> 
</template> 

闪光message.html

<template> 
    <div class="alert alert-success">${message}</div> 
</template> 

闪光message.js

import {bindable, bindingMode} from 'aurelia-framework'; 

export class FlashMessage { 
    @bindable({defaultBindingMode: bindingMode.twoWay}) message = 'Default'; 

    setMessage(newValue) { 
    this.message = newValue; 
    } 
} 

对象detail.js

import {FlashMessage} from './resources/elements/flash-message'; 

export class ObjectDetail { 
    static inject() {return [FlashMessage]}; 

    constructor(flash) { 
    this.flash = flash; 
    } 

    activate(params, routeConfig) { 
    this.flash.setMessage('Activate'); 
    } 
} 

activate()代码被调用以及所述setMessage()方法,但所显示的传递消息不更新。我错过了什么?

+1

由于自定义元素是用多个实例实例化的,因此您正在处理两个“FlashMessage”实例,因此其中一个实例的属性不会反映到另一个实例中。 – LStarky

回答

4

由于您最初只需要app.html中的模板而不实例化app.js中的类,Aurelia将它视为自定义元素,这意味着它具有自己的实例(不是单例)。您基本上正在处理两个不同的FlashMessage实例,因此其中一个的属性不会反映在另一个实例中。

如果您希望将它作为单例类实例化,则还需要导入app.js中的组件,并将其注入到构造函数中,以便将它视为组件而不是自定义元素。

app.js定义元素和类之间

import {FlashMessage} from './resources/elements/flash-message'; 

@inject(FlashMessage) 
export class App { 
    constructor(flashMessage) { 
    this.flashMessage = flashMessage; 
    } 
    // ... 
} 

混乱/视图模型

由于所有的类属性被认为是公开的,你甚至都不需要setMessage(newValue)方法。您可以从object-detail.js更新消息属性是这样的:

this.flash.message = 'Activate'; 

此外,@bindable行的目的是使用,让您可以在HTML代码中的变量值初始化它,就像这样:

<flash-message message="Show this message"></flash-message> 

如果你不打算像这样使用它,我会跳过整个@bindable行。你flash-message.js可以简化为仅仅这一点:对Flash的消息

export class FlashMessage { 
    constructor() { 
    this.message = 'Default'; 
    } 
} 

使用事件聚合的

我实现了有类似目标的一个Flash Message类,使用Toastr第三方库(只是因为我喜欢UI)。但是,以任何你想要的方式设置它并不难。我相信,允许应用程序的任何部分设置Flash消息的最佳方法是使用Aurelia的事件聚合器。以下代码片段可能会帮助您完成设置。

闪存message.js

import { inject } from 'aurelia-framework' 
import { EventAggregator } from 'aurelia-event-aggregator'; 

@inject(EventAggregator) 
export class FlashMessage { 

    constructor(eventAggregator) { 
    this.eventAggregator = eventAggregator; 
    this.eventAggregator.subscribe('ShowFlashMessage', this.showMessage); 
    } 

    showMessage(message) { 
    this.message = message; 
    // hide after 10 seconds 
    window.setTimeout(hideMessage, 10000); 
    } 

    hideMessage() { 
    this.message = ""; 
    } 
} 

这显然简化,并发布了第二条消息时,不会处理多条消息,或更新计时器,但它应该足以让你开始。

要设置从您的应用程序的其他部分的消息,你可以简单地先注入eventAggregator并保存在你的构造函数,然后发布这样的消息:

this.eventAggregator.publish('ShowFlashMessage', "Record saved"); 

在奥里利亚我Toastr实现:

给你做了什么一样,我在src文件夹中创建名为在一个名为commonFlashMessage一个共同的类。

//src/common/flash-message.js 
import * as toastr from 'toastr'; 
import { inject } from 'aurelia-framework' 
import { EventAggregator } from 'aurelia-event-aggregator'; 

@inject(EventAggregator) 
export class FlashMessage { 

    constructor(eventAggregator) { 
     this.eventAggregator = eventAggregator; 
     this.eventAggregator.subscribe('ewFlashSuccess', this.showSuccess); 
     this.eventAggregator.subscribe('ewFlashInfo', this.showInfo); 
     this.eventAggregator.subscribe('ewFlashWarning', this.showWarning); 
     this.eventAggregator.subscribe('ewFlashError', this.showError); 

     // Not sure why this is not working... if you figure it out, let me know. 
     toastr.options = { 
      positionClass: "toast-top-left", 
      showEasing: "swing", 
      hideEasing: "linear", 
      showMethod: "fadeIn", 
      hideMethod: "fadeOut", 
      preventDuplicates: true, 
      closeButton: true 
     } 
    } 

    showSuccess(message) { 
     toastr.success(message, null, {preventDuplicates: true, closeButton: true}); 
    } 

    showInfo(message) { 
     toastr.info(message, null, {preventDuplicates: true, closeButton: true}); 
    } 

    showWarning(message) { 
     toastr.warning(message, null, {preventDuplicates: true, closeButton: true}); 
    } 

    showError(message) { 
     toastr.error(message, null, {preventDuplicates: true, closeButton: true}); 
    } 

} 

然后,我注入和app.js这样的实例是:

import { inject } from 'aurelia-framework'; 
import { FlashMessage } from './common/flash-message'; 
@inject(Core, FlashMessage) 
export class App { 
    constructor(core, flashMessage) { 
    this.flashMessage = flashMessage; 
    } 
    // ... 
} 

我也不得不要求CSS在app.html这样的:

<require from="toastr/build/toastr.min.css"></require> 

所有这一切都取决于正确安装了Toastr(我使用npm install toastr --save进行了安装),并正确要求aurelia.json (我正在使用CLI)。

   { 
        "name": "toastr", 
        "path": "../node_modules/toastr", 
        "main": "toastr", 
        "resources": [ 
         "build/toastr.min.css" 
        ] 
       }, 

最后的想法

另请参阅阿什利格兰特的用于获取关于您的视图模型一个手柄以及工作GistRun来立即解决问题的一个更好的解释回应。阿什利比我在奥里利亚更有经验,所以如果我的解决方案的某些部分不起作用,他很可能会! :-)

+2

如果你想采取我发布的答案,并将其添加到你的感觉免费。 –

+0

谢谢,你太客气了!我感谢你为像我这样的“小家伙”留下一些空间来学习和成长!如果您在完全编辑的回复中看到任何错误或误导性内容,请通知我。 – LStarky

3

我建议使用view-model.ref="flash"来获取对自定义元素的ViewModel的引用。请注意,您将无法使用activate回调中的此功能,因为在页面生命周期的此点不会发生绑定。我在下面的示例中使用attached回调。

下面是一个例子:https://gist.run?id=76ef47a5327a34560737f4ade1038305

app.html

<template> 
    <require from="./flash-message"></require> 
    <flash-message view-model.ref="flash"></flash-message> 
</template> 

app.js

export class App { 
    attached(params, routeConfig) { 
    this.flash.setMessage('Activate'); 
    } 
} 

闪消息。HTML

<template> 
    <div class="alert alert-success">${message}</div> 
</template> 

闪存message.js

import {bindable, bindingMode} from 'aurelia-framework'; 

export class FlashMessage { 
    @bindable({defaultBindingMode: bindingMode.twoWay}) message = 'Default'; 

    setMessage(newValue) { 
    this.message = newValue; 
    } 
} 
3

从LStarky的消息时,我发现toastr这点我是不知道之前,所以我最终只是使用该库,而不是。

npm install toastr --save

aurelia.json(主管束 - >依赖关系)

{ 
    "name": "toastr", 
    "path": "../node_modules/toastr", 
    "main": "toastr", 
    "resources": [ 
    "build/toastr.min.css" 
    ] 
} 

app.html

<require from="toastr/build/toastr.min.css"></require> 

视图-model.js

import toastr from 'toastr'; 

action() { 
    toastr.success('Toastr visible!'); 
} 
+1

是的,这是我会建议的,老实说:-)干杯! –

+0

很高兴你找到了解决方案! – LStarky