2017-01-30 8 views
0

Я все еще пытаюсь найти ответ Aurelia JS - Making a synchronous HTTP request, to change data before page load? - поэтому в примере кода для этого вопроса я попробовал следующее: https://gist.run/?id=90d98563621fe49c1dde6b4f2fc6961d.Aurelia - доступ к обновленным свойствам класса из инъекций?

Согласно Aurelia - how to change bound variables, so the GUI changes?, я знаю, что я могу изменить переменную класса, являющуюся источником привязки HTML, и HTML/GUI должен обновиться. Поэтому я пытаюсь что-то подобное в gist выше - в частности, я пытаюсь изменить свойство массива contacts класса ContactListcontact-list.js).

Вот соответствующие изменения в app-clist.js:

import {WebAPI} from './web-api'; 
import {HttpClient} from 'aurelia-http-client'; 
import {ContactList} from './contact-list'; 
import {Container} from 'aurelia-dependency-injection'; 

// for multiline string, use backticks `` - ES6 template literals. 
let phpcode = ` 
<?php 
$outarr = array(); 

$tObj = new StdClass(); 
$tObj->{'id'} = '1'; 
$tObj->{'firstName'} = 'Bob'; 
$tObj->{'lastName'} = 'Glass'; 
$tObj->{'email'} = '[email protected]'; 
$tObj->{'phoneNumber'} = '243-6593'; 
array_push($outarr, $tObj); 
$tObj = new StdClass(); 
$tObj->{'id'} = '2'; 
$tObj->{'firstName'} = 'Chad'; 
$tObj->{'lastName'} = 'Connor'; 
$tObj->{'email'} = '[email protected]'; 
$tObj->{'phoneNumber'} = '839-2946'; 
array_push($outarr, $tObj); 

echo json_encode($outarr); 
?> 
`; 

export class AppClist { // in gist example is wrong, still called App 
    static inject() { return [WebAPI, HttpClient, ContactList]; } 

    constructor(api, http, conlist){ 
    this.api = api; 
    this.http = http; 
    this.conlist = conlist; 
    var phpcodesl = phpcode.replace(/(?:\r\n|\r|\n)/g, ' '); 
    var encphpcode = encodeURIComponent(phpcodesl); // urlencode 
    //alert(encphpcode); 
    // NOTE: gist.run due https will not allow loading from http 
    //this.http.post("https://phpfiddle.org/api/run/code/json", "code="+encphpcode) 
    //.then(response => {alert(response.response); console.log(response);}) // does not work 
    // this does work: 
    console.log("a1", this.conlist, this.conlist.contacts); 
    this.http.createRequest('https://phpfiddle.org/api/run/code/json') 
    .asPost() 
    .withHeader('Content-Type', 'application/x-www-form-urlencoded; charset=utf-8') 
    .withContent("code="+encphpcode) 
    .send() 
    .then(response => { 
     alert(response.response); 
     console.log(response); 
     var respobj = JSON.parse(response.response); 
     var respdataArr = JSON.parse(respobj.result); 
     this.api.setContactList(respdataArr); 
     console.log("a2", this.conlist, this.conlist.contacts, this.conlist.getThis(), Container.instance.get(ContactList)); 
    }).catch(err => { 
     console.log(err); 
    }) 
    ; 
    } 
... 

... и я добавил эту console.log заявление в contact-list.js:

created(){ 
    this.api.getContactList().then(contacts => { 
     this.contacts = contacts; 
     console.log("b1", this, this.contacts); }); 
    } 

..., а также эта функция в contact-list.js:

getThis(){ 
    return this; 
    } 

Однако, когда я запускаю этот (После нажатия на старт «жми меня» кнопку), я получаю это в журнале ошибок в Chromium браузер:

VM2198 app-clist.js!transpiled:48 

a1 ContactList {api: WebAPI, contacts: Array[0]} [] 
... 

contact-list.js:21 

b1 ContactList {api: WebAPI, __observers__: Object} [Object, Object, Object, Object, Object] 
... 

VM2198 app-clist.js!transpiled:55 

a2 ContactList {api: WebAPI, contacts: Array[0]} [] 
ContactList {api: WebAPI, contacts: Array[0]} 
ContactList {api: WebAPI, contacts: Array[0]} 
... 

Итак, вот как я интерпретирую это:

  • Сообщение a1 печатается в constructor()AppClist класс - и он запускается первым; в этот момент класс ContactList предоставляется через инъекцию как свойство класса AppClist под названием conlist. На данный момент, AppClist.conlist.contacts (то есть, ContactList.contacts) массив понятно пусто, и имеет размер 0.
  • Сообщение b1 печатается, когда ContactList компонент created(), после того, как ContactList.contacts массив инициализирован, и печатается второй - снова , как и ожидалось, в массиве есть 5 элементов
  • Сообщение a2 напечатано, когда HTTP-вызов завершен. Я ожидал бы 5 элементов в массиве contacts, но есть 0 (независимо от метода доступа)?!

Итак, мой вопрос: почему я получаю 0 как размер массива contacts, когда должно быть не менее 5? Может ли inject кэшировать состояние переменной/класса, к которому он должен ссылаться? Как я могу получить ссылку на последнее состояние свойства массива contacts класса ContactList в классе AppClist?

ответ

0

Ну, я думаю, что нашел исправление, хотя это все немного догадки, поэтому я по-прежнему буду признателен за правильный ответ от кого-то.

Во-первых, я думал, что этот вопрос «кэширование», но это похоже, что гораздо более вероятно, что, например, Container.instance.get(ContactList) возвращает новый экземпляр класса, а не один существующий экземпляр.Вот некоторые важные цитаты, которые я нашел:

Enhanced Dependency Injection Use · Issue #73 · aurelia/dependency-injection · GitHub предлагает использовать это:

// configure the container 
    let container = aurelia.container; 
    container.registerInstance(ApiClient, new ApiClient(isDebug)); 
    ... 
    aurelia.start().then(a => a.setRoot()); 
    ... 

... в main.js - Я пытался применять это к ContactList класса, но не мог получить мой пример работать ...

If Aurelia understands "import", why use dependency injection?

Это потому, что контейнер для инъекций Aurelia для инсталляции создает экземпляр для вас. ...
Вы говорите Аурелии: «Мне нужно одно из них, пожалуйста, дайте мне», и Аурелия говорит: «Конечно, я создал одну или у меня уже лежал, вот она».

Хм, ну, в моем примере, к тому времени мы получаем к «a2» лаг, Д. И. уже должен «знать», что он уже создал один ContactList - но, по-видимому все еще создает новый объект в любом случае ...

How to create a singleton service in Aurelia?

По умолчанию контейнер DI предполагает, что все одноэлементно экземпляр; один экземпляр для приложения. Однако вы можете использовать декоратор оформления, чтобы изменить это.

Ну, очевидно, это не предполагало, что для ContactList в приведенном выше примере?!

Решение для меня пришло из другого ответа в предыдущем посте, How to create a singleton service in Aurelia?:

Так я понял, что я думал об этом слишком сильно. Я пытался зависеть от структуры (Aurelia), чтобы выполнить всю работу, но на самом деле это было простое изменение класса ES6, которое делает его экземпляром.

... и вот как я применил это к ContactList классу, добавляя cl_instance переменную: (?!)

import {EventAggregator} from 'aurelia-event-aggregator'; 
import {WebAPI} from './web-api'; 
import {ContactUpdated, ContactViewed} from './messages'; 

let cl_instance = null; 

export class ContactList { 
    static inject = [WebAPI, EventAggregator]; 

    constructor(api, ea){ 
    if(!cl_instance) { 
    cl_instance = this; 

    this.api = api; 
    this.contacts = []; 

    ea.subscribe(ContactViewed, msg => this.select(msg.contact)); 
    ea.subscribe(ContactUpdated, msg => { 
     let id = msg.contact.id; 
     let found = this.contacts.find(x => x.id === id); 
     Object.assign(found, msg.contact); 
    }); 
    } // end if! 
    return cl_instance; 
    } 
    .... 

С этим, по-видимому, ContactList класса в настоящее время ведет себя как синглтон, и поэтому каждый раз, когда я прошу ссылки на экземпляр класса, я получаю тот же экземпляр класса (а не создаю новый экземпляр).

Это также означает, что теперь this.conlist.contacts в AppClist относится к фактической DataSource contacts переменной собственности в ContactList, и, таким образом, сопоставляя теперь вызывает связывание и обновляет графический интерфейс - который, таким образом, решает проблему в Aurelia JS - Making a synchronous HTTP request, to change data before page load? - Я сохранил, что пример для ссылки на https://gist.run/?id=f4bd01c99f9973cb76d8640f6248c2e3

 Смежные вопросы

  • Нет связанных вопросов^_^