[英]Aurelia JS - Making a synchronous HTTP request, to change data before page load?
我正在使用聯系人列表教程:
...並且我想更改它,因此該應用程序首先以“單擊我”按鈕開始。 單擊此按鈕后,應發出一個Web請求,該請求應返回JSON聯系人數據。 如果請求成功,則響應應更新聯系人的主數據存儲,並且頁面應從呈現新的聯系人列表開始; 如果請求失敗,則頁面應顯示原始(硬編碼)聯系人列表。
原始聯系人列表應用的副本可以在https://gist.run/?id=c73b047c8184c052b4c61c69febb33d8 (僅適用於Chrome)上找到; 而我為實現上述目的所做的更改位於:
這是我嘗試做的-首先,對開始按鈕進行了更改(在Aurelia JS中也是如此-無法通過單擊導航父級(未找到路由)? )。 *然后,在web-api.js
有一個新的setContactList
函數,該函數應允許更改數據容器變量。 *單擊開始“單擊我”按鈕后,將加載app-clist.*
。 在app-clist.js
,有PHP代碼構成了一個新的聯系人列表,並且由於我沒有上載和運行服務器PHP代碼的簡便方法,因此我將該PHP代碼發送到http://phpfiddle.org進行處理並返回結果(另請參見https://softwarerecs.stackexchange.com/questions/39075/web-service-for-sharing-and-serving-php-code/39078#39078 )這是在constructor()
函數中完成的,因此, app-clist.js
的對象第一次加載(即在單擊“開始”按鈕之后)。 如果此Web調用成功,則將調用setContactList
來更改聯系人列表。
因此,這里的問題是-網頁調用全部成功,但是它們發生得太晚了-在呈現頁面之后。 單擊開始按鈕后,首先呈現頁面(包含舊聯系人); 然后我收到警報:
An embedded page at gist.host says:
{"result":"[{\"id\":\"1\",\"firstName\":\"Bob\",\"lastName\":\"Glass\",\"email\":\"bob@glass.com\",\"phoneNumber\":\"243-6593\"},{\"id\":\"2\",\"firstName\":\"Chad\",\"lastName\":\"Connor\",\"email\":\"chad@connor.com\",\"phoneNumber\":\"839-2946\"}]"}
...這表示網絡通話成功,然后出現了第二次警報:
An embedded page at gist.host says:
setContactList 2 2
...表明接收到的聯系人數組的長度與原始聯系人數組的長度相同,這意味着更新已發生。 除了,它發生得很晚。
這提醒我JavaScript中的HTTP調用通常是異步的-即它們將僅啟動該過程,並且在完成之前不會阻塞其余代碼。 我使用過的aurelia-http-client
可能就是這種情況:
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);
}).catch(err => {
console.log(err);
});
因此,對於我的概念-我是在頁面的生命周期開始時調用服務,該服務返回應該在第一次放映時顯示在頁面上的數據-我必須進行同步調用,這會阻止在app-clist
執行constructor()
直到完成(成功或失敗),以便可以在頁面呈現開始之前更新數據...
所以我的問題是:如何使用Aurelia JS進行同步HTTP調用? 或者,是否可以通過異步調用來實現類似於我的示例的功能,如果可以,如何執行?
以下是一些更相關的文件供參考:
app-clist.html
<template>
<require from="bootstrap/css/bootstrap.css"></require>
<require from="./styles.css"></require>
<require from="./contact-list"></require>
<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
<div class="navbar-header">
<a class="navbar-brand" href="#">
<i class="fa fa-user"></i>
<span>Contacts</span>
</a>
</div>
</nav>
<div class="container">
<div class="row">
<contact-list class="col-md-4"></contact-list>
<router-view name="chldrt" class="col-md-8"></router-view>
</div>
</div>
</template>
app-clist.js
import {WebAPI} from './web-api';
import {HttpClient} from 'aurelia-http-client';
// 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'} = 'bob@glass.com';
$tObj->{'phoneNumber'} = '243-6593';
array_push($outarr, $tObj);
$tObj = new StdClass();
$tObj->{'id'} = '2';
$tObj->{'firstName'} = 'Chad';
$tObj->{'lastName'} = 'Connor';
$tObj->{'email'} = 'chad@connor.com';
$tObj->{'phoneNumber'} = '839-2946';
array_push($outarr, $tObj);
echo json_encode($outarr);
?>
`;
export class AppClist { // in gist, it is mistakenly still App
static inject() { return [WebAPI, HttpClient]; }
constructor(api, http){
this.api = api;
this.http = http;
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:
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);
}).catch(err => {
console.log(err);
})
;
}
// no configureRouter(config, router){ here same as in app.js!
/**/configureRouter(config, router){
config.title = 'Contacts';
config.map([
// must include empty route '' here, else "Route not found" at start
{ route: ['','contacts'], viewPorts: { chldrt: { moduleId: 'no-selection' } }, title: 'Select'},
{ route: 'contacts/:id', viewPorts: { chldrt: { moduleId: 'contact-detail' } }, name:'contacts' }
]);
this.router = router;
}
}
app.html
<template>
<require from="bootstrap/css/bootstrap.css"></require>
<require from="./styles.css"></require>
<require from="./contact-list"></require>
<loading-indicator loading.bind="router.isNavigating || api.isRequesting"></loading-indicator>
<router-view name="mainrt"></router-view>
</template>
app.js
import {WebAPI} from './web-api';
export class App {
static inject() { return [WebAPI]; }
constructor(api) {
this.api = api;
}
configureRouter(config, router){
config.title = 'App Contacts';
config.map([
{ route: '', viewPorts: { mainrt: { moduleId: 'btn-start' } }, title: 'Start'},
{ route: 'app-clist', viewPorts: { mainrt: { moduleId: 'app-clist' }, chldrt: { moduleId: 'no-selection' } }, name: 'app-clist', title: 'C List'} //,
//{ route: 'contacts', viewPorts: { chldrt: { moduleId: 'no-selection' } }, title: 'Select'},
//{ route: 'contacts/:id', viewPorts: { chldrt: { moduleId: 'contact-detail' } }, name:'contacts' }
]);
this.router = router;
}
}
btn-start.html
<template>
<div id="startbtn" click.trigger="goClist()">Click here to start!</div>
</template>
btn-start.js
import {WebAPI} from './web-api';
import { Router } from 'aurelia-router';
import {App} from './app';
export class BtnStart {
static inject() { return [WebAPI, Router, App]; }
constructor(api, router, app) {
this.api = api;
this.router = router;
this.app = app;
}
goClist() {
this.app.router.navigateToRoute("app-clist");
}
}
web-api.js
let latency = 200;
let id = 0;
function getId(){
return ++id;
}
let contacts = [
{
id:getId(),
firstName:'John',
lastName:'Tolkien',
email:'tolkien@inklings.com',
phoneNumber:'867-5309'
},
{
id:getId(),
firstName:'Clive',
lastName:'Lewis',
email:'lewis@inklings.com',
phoneNumber:'867-5309'
},
{
id:getId(),
firstName:'Owen',
lastName:'Barfield',
email:'barfield@inklings.com',
phoneNumber:'867-5309'
},
{
id:getId(),
firstName:'Charles',
lastName:'Williams',
email:'williams@inklings.com',
phoneNumber:'867-5309'
},
{
id:getId(),
firstName:'Roger',
lastName:'Green',
email:'green@inklings.com',
phoneNumber:'867-5309'
}
];
export class WebAPI {
isRequesting = false;
setContactList(incontacts) {
contacts = incontacts;
alert("setContactList " + incontacts.length + " " + contacts.length);
console.log("setContactList", incontacts, contacts);
}
getContactList(){
this.isRequesting = true;
return new Promise(resolve => {
setTimeout(() => {
let results = contacts.map(x => { return {
id:x.id,
firstName:x.firstName,
lastName:x.lastName,
email:x.email
}});
resolve(results);
this.isRequesting = false;
}, latency);
});
}
getContactDetails(id){
this.isRequesting = true;
return new Promise(resolve => {
setTimeout(() => {
let found = contacts.filter(x => x.id == id)[0];
resolve(JSON.parse(JSON.stringify(found)));
this.isRequesting = false;
}, latency);
});
}
saveContact(contact){
this.isRequesting = true;
return new Promise(resolve => {
setTimeout(() => {
let instance = JSON.parse(JSON.stringify(contact));
let found = contacts.filter(x => x.id == contact.id)[0];
if(found){
let index = contacts.indexOf(found);
contacts[index] = instance;
}else{
instance.id = getId();
contacts.push(instance);
}
this.isRequesting = false;
resolve(instance);
}, latency);
});
}
}
好吧,我終於設法進行了一個異步調用,該更新按照@LStarky的建議更新了GUI。 請注意,為此,必須確保ContactList
類是單個實例類,以便只有一個屬性contacts
的綁定會更新HTML GUI。
但是,由於所有這些都有些虛假的猜測,因此從某個人那里獲得正確的答案仍然很不錯。
單實例問題在以下內容中描述:
作為參考,我將工作示例保存為要點。在這里運行:
...因此,基本上,在兩次警報之后,顯示的聯系人將使用從PHP頁面獲取的數據進行更新。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.