skip to Main Content

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


  1. You are getting data asynchronous

    • So this.jsonProps is undefined until the getData() function received it:

    • Move the render() call

    • (and no need for a costly <template> to create HTML)

    class ResultGrid extends HTMLElement {
        constructor() {
            super();
        }
    
        connectedCallback() {
            this.getData();
        }
    
        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
    
                    // !! NOW .render() can access this.jsonProps
                    this.attachShadow({mode:"open"}).innerHTML = this.render();
    
                }
            } catch(e) {
                console.error(e.message);
            }
        }
    
    Login or Signup to reply.
  2. 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()

    class ResultGrid extends HTMLElement {
        constructor() {
            super();
        }
    
        connectedCallback() {
            (async () => {
                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 {
                        let template = document.createElement("template");
                        template.innerHTML = this.render(await res.json());
                        this.attachShadow({mode: "open"});
                        this.shadowRoot.appendChild(template.content.cloneNode(true));
                    }
                } catch(e) {
                    console.error(e.message);
                }
            })();
        }
    

    and update the render method

    render(jsonProps: Record<string, string | string[]>) {
            return (`
                <style>
                    #grid {
                        display: grid;
                        width: 40vw;
                        grid-template-columns: 1fr 1fr;
                    }
                </style>
    
                <div id="grid">
                    <div>Nama</div>
                    <div>${jsonProps.nama}</div>
                    <div>Nrp</div>
                    <div>${jsonProps.nrp}</div>
                    <div>Kelas</div>
                    <div>${jsonProps.kelas}</div>
                    <div>Jenis Kelamin</div>
                    <div>${jsonProps.kelamin}</div>
                    <div>Agama</div>
                    <div>${jsonProps.agama}</div>
                    <div>Tempat</div>
                    <div>${jsonProps.tempat}</div>
                    <div>Tanggal lahir</div>
                    <div>${jsonProps.tgl}</div>
                    <div>Alamat</div>
                    <div>${jsonProps.alamat}</div>
                    <div>SD</div>
                    <div>${jsonProps.sd}</div>
                    <div>SMP</div>
                    <div>${jsonProps.smp}</div>
                    <div>SMA</div>
                    <div>${jsonProps.sma}</div>
                    <div>Email</div>
                    <div>${jsonProps.email}</div>
                    <div>Homepage</div>
                    <div>${jsonProps.homepage}</div>
                    <div>Hobby</div>
                    <div>${jsonProps.hobby}</div>
                    <div>Interest</div>
                    <div>${(jsonProps.interests as string[]).map((itr: string) => itr)}</div>
                    <button onclick="router()">return</button>
                </div>
            `);
        }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search