如何在Aurelia中设置Flash消息?

时间:2016-12-22 23:59:40

标签: aurelia aurelia-binding

我正试图弄清楚如何在Aurelia制作flash消息。我创建了一个自定义元素var margin = {top: 20, right: 20, bottom: 50, left: 70}, width = 400 - margin.left - margin.right, height = 400 - margin.top - margin.bottom, delim = 4; var scale = d3.scaleLinear() .domain([0, 21]) .rangeRound([height, 0]); var x = d3.scaleLinear() .domain([0, barData.length]) .rangeRound([0, width]); var y = d3.scaleLinear() .domain([0, 21]) .rangeRound([height, 0]); var svg = d3.select('#chart') .append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append('g') .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); svg.append("g") .attr("transform", "translate(0," + height + ")") .call(d3.axisBottom(x)); svg.append("g") .call(d3.axisLeft(y)); function draw() { x.domain([0, barData.length]); var brush = d3.brushY() .extent(function (d, i) { return [[x(i)+ delim/2, 0], [x(i) + x(1) - delim/2, height]];}) .on("brush", brushmove); var svgbrush = svg.selectAll('.brush').data(barData); svgbrush.enter() .append('g') .attr('class', 'brush') .merge(svgbrush) .append('g') .call(brush) .call(brush.move, function (d){return [d.value, 0].map(scale);}); svgbrush.exit().remove(); svgbrush .append('text') .attr('y', function (d){return scale(d.value) + 25;}) .attr('x', function (d, i){return x(i) + x(0.5);}) .attr('dx', '-.60em') .attr('dy', -5) .style('fill', 'white') .text(function (d) {return d3.format('.2')(d.value);}) function brushmove() { var d0 = d3.event.selection.map(scale.invert); var d = d3.select(this).select('.selection');; var d1 =[d0[0], 0]; if (!d3.event.sourceEvent) return; if (!d3.event.selection) return; if (d3.event.sourceEvent.type === "brush") return; d.datum().value = d0[0]; d3.select(this).call(d3.event.target.move, d1.map(scale)); svgbrush .selectAll('text') .attr('y', function (d){return scale(d.value) + 25;}) .text(function (d) {return d3.format('.2')(d.value);}); } draw(); function upadateChartData() { var newBarsToAdd = document.getElementById('charBarsCount').value; var newBarData = function() { return { index: _.uniqueId(), value: _.random(1, 20) } }; newBarData = _.times(newBarsToAdd, newBarData); barData = _.concat(barData, newBarData) draw(); }; ,并在flash-message中需要它,但邮件不会更新。如果我将其设置为默认值,它会正确显示。

app.html

app.html

闪message.html

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

闪message.js

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

对象detail.js

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

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

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

正在调用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()方法,但显示的消息未更新。我错过了什么?

3 个答案:

答案 0 :(得分:5)

由于您最初只需要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;
  }
  // ...
}

自定义元素与类/ ViewModel之间的混淆

由于所有类属性都被视为公共属性,因此您甚至不需要setMessage(newValue)方法。您可以像object-detail.js这样更新邮件属性:

this.flash.message = 'Activate';

此外,还要使用@bindable行,以便您可以使用HTML代码中的变量值对其进行实例化,如下所示:

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

如果您不打算像这样使用它,我会跳过整个@bindable行。您的flash-message.js可以简化为:

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

使用事件聚合器进行Flash消息

我使用Toastr第三方库实现了一个具有类似目标的Flash Message类(仅仅因为我喜欢用户界面)。但是以任何你想要的方式设置它并不难。我认为,允许应用程序的任何部分设置Flash消息的最佳方法是使用Aurelia的Event Aggregator。以下代码段可能会帮助您进行设置。

<强>闪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");

我在Aurelia的Toastr实施:

与您所做的类似,我在FlashMessage文件夹中名为common的子文件夹中创建了一个名为src的公共类。

//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;
  }
  // ...
}

我还必须像app.html这样要求CSS:

<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"
                    ]
                },

最后的想法

另请参阅Ashley Grant的回复,以便更好地解释如何获取ViewModel,以及使用GistRun来解决您的紧急问题。 Ashley比Aurelia更有经验,所以如果我的部分解决方案不起作用,那么他最有可能! : - )

答案 1 :(得分: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');
  }
}

<强>闪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;
  }
}

答案 2 :(得分:3)

从LStarky的消息中,我发现了之前我不知道的事情,所以我最后只是使用了那个库。

npm install toastr --save

aurelia.json (在bundle - &gt;依赖项下)

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