i want to create a component that get json data from php server, the data then i put in ResultGrid
class property, named jsonProps
i defined the property and typescript didn’t complain, however, when i ran the code in the browser, the property that i set isn’t recognize by the browser, here’s the code
i also tried using setter in typescript, it didn’t work(the typescript code that i post didn’t use it, but the previous version )
The HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>File</title>
</head>
<body>
</body>
<script src="ract.js"></script>
</html>
The Typescript code (ract.ts)
let SHOW: boolean = false;
class InputText extends HTMLElement {
constructor() {
super();
let template = document.createElement("template");
template.innerHTML = this.render();
this.attachShadow({mode: "open"});
this.shadowRoot.appendChild(template.content.cloneNode(true));
}
render(): string {
return(`
<div>
1. Nama:
<input type="text" name="nama">
</div>
<div>
2. NRP:
<input type="text" name="nrp">
</div>
<div>
3. Kelas:
<input type="text" name="kelas">
</div>
<div>
4. Jenis kelamin:
<input type="radio" name="kelamin" value="pria">
Pria
<input type="radio" name="kelamin" value="wanita">
Wanita
</div>
<div>
5. Agama:
<select name="agama">
<option value="islam">Islam</option>
<option value="kristen">Kristen</option>
<option value="katolik">Katolik</option>
<option value="hindu">Hindu</option>
<option value="budha">Budha</option>
<option value="konghucu">Konghucu</option>
</select>
</div>
<div>
6. Tempat / Tanggal lahir:
<input type="text" name="tempat">
<input type="text" name="tgl">
</div>
<div>
7. Alamat
</div>
<textarea name="alamat" cols="30" rows="10"></textarea>
<div>
8. Riwayat pendidikan:
<ul type="a">
<li>
SD:
<input type="text" name="sd">
</li>
<li>
SMP:
<input type="text" name="smp">
</li>
<li>
SMA:
<input type="text" name="sma">
</li>
</ul>
</div>
<div>
9. Email
<input type="email" name="email">
</div>
<div>
10. Homepage
<input type="url" name="homepage">
</div>
<div>
11. Hobby
</div>
<textarea name="hobby" cols="30" rows="10"></textarea>
<div>
12. interest:
<input type="checkbox" name="interest1" value="komputer">
komputer
<input type="checkbox" name="interest2" value="sport">
sport
<input type="checkbox" name="interest3" value="travelling">
travelling
<input type="checkbox" name="interest4" value="writing">
writing
<input type="checkbox" name="interest5" value="reading">
reading
</div>
<div>
<button onclick="router()">Simpan</button>
<button type="reset">Reset</button>
</div>
`);
}
}
class ResultGrid extends HTMLElement {
jsonProps: Record<string, string | string[]>;
constructor() {
super();
this.jsonProps; // this property is undefined in the browser
}
connectedCallback() {
this.getData();
let template = document.createElement("template");
template.innerHTML = this.render();
this.attachShadow({mode: "open"});
this.shadowRoot.appendChild(template.content.cloneNode(true));
}
async getData() {
let url = // read.php url;
try {
let res = await fetch(url, {
headers: {
'Accept': 'application/json;text/plain'
}
});
if(res.status !== 200) {
throw new Error(await res.text());
} else {
this.jsonProps = await res.json(); // setting property here
}
} catch(e) {
console.error(e.message);
}
}
render() {
return (`
<style>
#grid {
display: grid;
width: 40vw;
grid-template-columns: 1fr 1fr;
}
</style>
<div id="grid">
<div>Nama</div>
<div>${this.jsonProps.nama}</div>
<div>Nrp</div>
<div>${this.jsonProps.nrp}</div>
<div>Kelas</div>
<div>${this.jsonProps.kelas}</div>
<div>Jenis Kelamin</div>
<div>${this.jsonProps.kelamin}</div>
<div>Agama</div>
<div>${this.jsonProps.agama}</div>
<div>Tempat</div>
<div>${this.jsonProps.tempat}</div>
<div>Tanggal lahir</div>
<div>${this.jsonProps.tgl}</div>
<div>Alamat</div>
<div>${this.jsonProps.alamat}</div>
<div>SD</div>
<div>${this.jsonProps.sd}</div>
<div>SMP</div>
<div>${this.jsonProps.smp}</div>
<div>SMA</div>
<div>${this.jsonProps.sma}</div>
<div>Email</div>
<div>${this.jsonProps.email}</div>
<div>Homepage</div>
<div>${this.jsonProps.homepage}</div>
<div>Hobby</div>
<div>${this.jsonProps.hobby}</div>
<div>Interest</div>
<div>${(this.jsonProps.interests as string[]).map((itr: string) => itr)}</div>
<button onclick="router()">return</button>
</div>
`);
}
}
(function init() {
customElements.define("input-text", InputText);
customElements.define("result-grid", ResultGrid);
let input = document.createElement("input-text");
document.body.appendChild(input);
})()
function router() {
if(SHOW === false) {
(async () => {
let inputShadow = document.querySelector("input-text").shadowRoot;
const url: string = // savetofile.php url;
let intagr: string[] = [];
(function() {
(inputShadow.querySelector('input[name="interest1"]') as HTMLInputElement).checked &&
intagr.push((inputShadow.querySelector('input[name="interest1"]') as HTMLInputElement).value);
(inputShadow.querySelector('input[name="interest2"]') as HTMLInputElement).checked &&
intagr.push((inputShadow.querySelector('input[name="interest2"]') as HTMLInputElement).value);
(inputShadow.querySelector('input[name="interest3"]') as HTMLInputElement).checked &&
intagr.push((inputShadow.querySelector('input[name="interest3"]') as HTMLInputElement).value);
(inputShadow.querySelector('input[name="interest4"]') as HTMLInputElement).checked &&
intagr.push((inputShadow.querySelector('input[name="interest4"]') as HTMLInputElement).value);
(inputShadow.querySelector('input[name="interest5"]') as HTMLInputElement).checked &&
intagr.push((inputShadow.querySelector('input[name="interest5"]') as HTMLInputElement).value);
})();
let send: Record<string, string | string[]> = {
nama: (inputShadow.querySelector('input[name="nama"]') as HTMLInputElement).value,
nrp: (inputShadow.querySelector('input[name="nrp"]') as HTMLInputElement).value,
kelas: (inputShadow.querySelector('input[name="kelas"]') as HTMLInputElement).value,
kelamin: (inputShadow.querySelector('input[name="kelamin"]') as HTMLInputElement).value,
agama: (inputShadow.querySelector("select") as HTMLSelectElement).value,
tempat: (inputShadow.querySelector('input[name="tempat"]') as HTMLInputElement).value,
tgl: (inputShadow.querySelector('input[name="tgl"]') as HTMLInputElement).value,
alamat: (inputShadow.querySelector('textarea[name="alamat"]') as HTMLTextAreaElement).value,
sd: (inputShadow.querySelector('input[name="sd"]') as HTMLInputElement).value,
smp: (inputShadow.querySelector('input[name="smp"]') as HTMLInputElement).value,
sma: (inputShadow.querySelector('input[name="sma"]') as HTMLInputElement).value,
email: (inputShadow.querySelector('input[name="email"]') as HTMLInputElement).value,
homepage: (inputShadow.querySelector('input[name="homepage"]') as HTMLInputElement).value,
hobby: (inputShadow.querySelector('textarea[name="hobby"]') as HTMLTextAreaElement).value,
interests: intagr
}
try {
let res = await fetch(url, {
method: 'POST',
body: JSON.stringify(send),
headers: {
'Content-type': "application/json",
'Accept': "text/plain"
}
});
if(res.status !== 200) {
let text = await res.text();
throw new Error(text);
}
} catch (error) {
alert(error.message);
}
})();
document.querySelector("input-text").remove();
let resultPage = document.createElement("result-grid");
document.body.appendChild(resultPage);
SHOW = true;
} else {
document.querySelector("result-grid").remove();
let inputPage = document.createElement("input-text");
document.body.appendChild(inputPage);
SHOW = false;
}
}
savetofile.php code
<?php
$request = json_decode(file_get_contents("php://input"), true);
header('Accept: application/json');
header('Content-type: text/plain');
$fp = fopen("data.json", "w");
if(!$fp) {
http_response_code(500);
echo "failed to create file";
} else {
fwrite($fp, json_encode($request));
http_response_code(200);
fclose($fp);
}
?>
read.php code
<?php
try {
$filename = './data.json';
$json_file = fopen($filename, 'r');
if(!$json_file) {
throw new Exception("error opening file", 1);
} else {
header("Content-type: application/json");
$read_file = fread($json_file, filesize($filename));
echo json_encode(json_decode($read_file));
}
fclose();
} catch (Exception $th) {
header("Content-type: text/plain");
http_response_code(500);
echo $th->getMessage();
}
?>
here’s also my tsconfig
tsconfig.json
{
"compilerOptions": {
"target": "esnext",
"module": "commonjs",
"lib": ["ESNext", "DOM"],
"noImplicitAny": true,
"preserveConstEnums": true,
"outDir": "./",
"sourceMap": true
},
"include": ["ract.ts"],
"exclude": ["node_modules", "**/*.spec.ts"]
}
the error message is:
Uncaught TypeError: this.jsonProps is undefined
2
Answers
You are getting data asynchronous
So
this.jsonProps
isundefined
until thegetData()
function received it:Move the
render()
call(and no need for a costly
<template>
to create HTML)as suggested by @danny-365csi-engelman
and after reading
How do I return the response from an asynchronous call?
Why is my variable unaltered after I modify it inside of a function? – Asynchronous code reference
i moved the entire async function inside connectedCallback()
and update the render method