Аурелия общий класс / модель

Я пытаюсь реализовать общедоступный единственный класс в проекте Aurelia. Цели заключаются в том, чтобы (а) сохранять отдельные состояния / состояния, такие как текущий идентификатор пользователя / имя / разрешения, (б) загружать и хранить общие данные, такие как списки перечислений и пары ключ-значение, для раскрывающихся списков по всему приложению, (в) хранить часто используемые функции, такие как оболочки для клиента Http-Fetch, (d) настраивают и затем обновляют локаль i18n, (e) глобальный прослушиватель клавиатуры для горячих клавиш во всем приложении. Вот что у меня так далеко:

/src/resources/components/core.js:

import 'fetch';
import { HttpClient, json } from 'aurelia-fetch-client';
import { inject } from 'aurelia-framework';
import { EventAggregator } from 'aurelia-event-aggregator';
import { BindingSignaler } from 'aurelia-templating-resources';
import { I18N } from 'aurelia-i18n';
import * as store from 'store';

@inject(EventAggregator, BindingSignaler, I18N, HttpClient)
export class Core {

  constructor(eventAggregator, bindingSignaler, i18n, httpClient) {
    // store local handles
    this.eventAggregator = eventAggregator;
    this.bindingSignaler = bindingSignaler;
    this.i18n = i18n;

    // initialize singulars
    this.UserID = 1;
    this.lang = 'es';
    this.yr = 78;
    this.qtr = 1;

    // set up httpClient
    httpClient.configure(config => {
      config
        .withBaseUrl('http://localhost:8080/api/v1');
    });
    this.httpClient = httpClient;

    // listen for Ctrl+S or Ctrl+Enter and publish event
    window.addEventListener("keydown", (event) => {
      if (event.ctrlKey || event.metaKey) { // Ctrl + ___
        if ((event.keyCode == 83) || (event.keyCode == 115) || (event.keyCode == 10) || (event.keyCode == 13)) {  // Ctrl+Enter or Ctrl+S
          // Save button... publish new event
          event.preventDefault();
          this.eventAggregator.publish('ewKeyboardShortcutSave', true);
        }
        if ((event.keyCode == 77) || (event.keyCode == 109)) {  // Ctrl+M
          // New button... publish new event
          event.preventDefault();
          this.eventAggregator.publish('ewKeyboardShortcutNew', true);
        }
      }
    });

    // load enumData
    $.getJSON("../../locales/" + this.lang + "/enum.json", (json) => { this.enum = json; });
    this.getTableKeys();
    this.getEnumCats();
  }

  getData(url) {
    // Http Fetch Client to retreive data (GET)
    return this.httpClient.fetch(url)
      .then(response => response.json());
  }

  postData(url, data, use_method = 'post') {
    // Http Fetch Client to send data (POST/PUT/DELETE)
    return this.httpClient.fetch(url, {
      method: use_method,
      body: json(data)
    }).then(response => {
      if (!response.ok) {
        throw Error(response.statusText);
      }
      return response;
    });
  }

  getTableKeys() {
    // retrieve list of table keys from database API
    this.getData('/keys').then(response => {
      this.keys = response;
    });
  }

  getEnumCats() {
    // retrieve list of enum cats from database API
    this.getData('/enums').then(response => {
      this.cats = response;
    });
  }

  setLang(lang) {
    if (lang) {
      this.lang = lang;
    }
    // set i18n locale
    this.i18n.setLocale(this.lang);
    // load enumData
    $.getJSON("../../locales/" + this.lang + "/enum.json", (json) => {
      this.enumData = json;
    });
    // publish new event
    this.eventAggregator.publish('ewLang', lang);
    this.bindingSignaler.signal('ewLang');
  }
}

Вот /src/resources/index.js для функции ресурсов:

export function configure(config) {

  // value converters
  config.globalResources([
    './value-converters/currency-format-value-converter',
    './value-converters/number-format-value-converter',
    './value-converters/date-format-value-converter',
    './value-converters/checkbox-value-converter',
    './value-converters/keys-value-converter',
    './value-converters/enum-value-converter',
    './value-converters/table-key-value-converter'
    ]);

  // custom elements
  config.globalResources([
    './elements/enum-list',
    './elements/modal-form'
    ]);

  // common/core components
  config.globalResources([
    './components/core'
    ]);
}

который в свою очередь активируется в моем main.js следующим образом:

export function configure(aurelia) {
  aurelia.use
    .standardConfiguration()
    .feature('resources')
    // .plugin('aurelia-dialog') // not working
    .plugin('aurelia-validation')
    .plugin('aurelia-i18n', (instance) => {
      // register backend plugin
      instance.i18next.use(XHR);
      instance.setup({
        backend: {                                  
          loadPath: '/locales/{{lng}}/{{ns}}.json',
        },
        lng : 'en',
        ns: ['translation'],
        defaultNS: 'translation',
        attributes : ['t'],
        fallbackLng : 'en',
        debug : false
      });
    });

  aurelia.start().then(a => a.setRoot());
}

Вопросы:

  1. Это не работает. Я получаю две ошибки: vendor-bundle.js:3777 Uncaught TypeError: h.load is not a function а также Unhandled rejection Error: Load timeout for modules: template-registry-entry!resources/components/core.html,text!resources/components/core.html, Любая идея, почему он пытается найти core.html, когда мне нужен только компонент core.js?

  2. Можно ли даже глобально внедрить этот тип класса таким образом, чтобы моим моделям представления не нужно было внедрять его, но он все еще мог получить доступ к свойствам, или мне все еще нужно внедрять этот файл везде?

  3. Является ли имя файла core.js и имя класса Core приемлемыми для именования? Является ли расположение внутри / src / resources / components хорошим выбором? Я должен был создать подпапку компонентов.

  4. Любые другие предложения для лучшей передовой практики?

1 ответ

Решение

Вопрос 1

Когда вы делаете это:

config.globalResources([
'./components/core'
]);

Aurelia попытается загрузить пару view и view-model, соответственно core.js и core.html, если только компонент не объявлен как "компонент только для view-модели". Как это:

import { noView } from 'aurelia-framework';

@noView
@inject(EventAggregator, BindingSignaler, I18N, HttpClient)
export class Core {
}

В вышеупомянутом случае Aurelia не будет пытаться загрузить "core.html", потому что компонент объявлен с noView,

вопрос 2

Насколько я знаю, вы должны inject или же <require> это везде, но последнее не применимо в вашем случае, поэтому вы должны inject, Вы можете обмануть, чтобы избежать инъекций, но я бы не советовал.

Вопрос 3

Имя файла core.js и имя класса Core не только приемлемо, но и правильный aurelia-способ сделать это. Тем не менее, я не думаю, что "/resources/components" является хорошим местом, потому что это не компонент, даже не "ресурс". Я бы переместил это в другую папку.

Кроме того, удалите эти строки:

config.globalResources([
'./components/core'
]);

Ресурсы были сделаны для использования внутри представлений, а это не так.

Вопрос 4

Файл core.js кажется очень важной частью кода вашего приложения. Я бы оставил его внутри корневой папки, рядом с main.js. (ЭТО МОЕ МНЕНИЕ)

Кроме того, если вам нужно установить некоторые конкретные свойства в вашем Core объект, вы можете создать его экземпляр в main.js. Что-то вроде этого:

export function configure(aurelia) {
   //...

   Core core = new Core(); //<--- put necessary parameters
   //some default configuration
   aurelia.container.registerInstance(Core, core);      

  aurelia.start().then(a => a.setRoot());
}

Теперь вы можете ввести core объект с помощью @inject декоратор и все классы будут иметь один и тот же экземпляр Core, Более подробная информация на http://aurelia.io/hub.html#/doc/article/aurelia/dependency-injection/latest/dependency-injection-basics/1.

Надеюсь это поможет!

Другие вопросы по тегам