Reputation: 3461
I was trying to get a list through an ajax call but before it gets resolved, render()
method is being called and the template fragment dependent on the Promise was not able to resolve and throws undefined.
Question: How to show a loader till I get the data from the Promise?
import {
LitElement,
html
} from 'lit-element';
class EmpComponent extends LitElement {
constructor() {
super();
this.data = this.getEmpData();
}
getEmpData() {
fetch('../../../emp-data.json')
.then(
function(response) {
if (response.status !== 200) {
console.log('Looks like there was a problem. Status Code: ' +
response.status);
return;
}
response.json().then(data => data);
}
)
.catch(function(err) {
console.log('Fetch Error :-S', err);
});
}
render() {
<div>
${this.data.map(emp => emp.active ? this.dataTemplate(emp) : '')}
</div>
}
}
customElements.define('emp-component', EmpComponent);
Getting this error:
Upvotes: 0
Views: 1142
Reputation: 593
step 1: create a js
file that return true
or false
(e.g. util.js)
export function when(expression, truVal, falseVal) {
if (expression) {
return truVal();
}
if (falseVal) {
return falseVal();
}
return undefined;
}
step 2: import util in your js
file
import {
LitElement,
html
} from 'lit-element';
import {
when
} from 'util.js'
step 3: set a isLoading
property in static get properties
. So on inital load, we set onload
to true in constructor
import {
LitElement,
html
} from 'lit-element';
import {
when
} from 'util.js'
class EmpComponent extends LitElement {
static get properties() {
return {
isLoading: {
type: Boolean
},
}
}
constructor() {
super();
this.isLoading = true;
}
step 4: once data is fetched, we are ready to render DOM. Then we can set isLoading
to false and then render DOM using when
static get properties() {
return {
isLoading: {
type: Boolean
},
canRender: {
type: Boolean
}
}
}
constructor() {
super();
this.isLoading = true;
this.canRender = false;
this.data = this.getEmpData();
this.isLoading = false;
this.canRender = true;
}
render() {
return html `
${when(this.isLoading,() => html`<p>Loading...</p>`)}
${when(this.canRender,() => html`<your-component></your-component>`)}
`
}
This is an alternate solution for until
. you can get more details from this blog sabarinath blog
Upvotes: 2
Reputation: 2111
I comment the parts where you should make changes. You don't need to do weird things with other imports
import { LitElement, html } from 'lit-element';
class EmpComponent extends LitElement
{
constructor() {
super();
// you were returning a promise to an Array type...
// this.data = this.getEmpData();
// Correct
this.data = [];
this.getEmpData();
}
// ADD PROPS
static get properties() {
return {
data: {type:Array}
};
}
getEmpData() {
fetch('../../../emp-data.json')
.then(()=>(response) {
if (response.status !== 200) {
console.log('Looks like there was a problem. Status Code: ' +
response.status);
return;
}
// SET DATA ON RESOLVE
response.json().then(data => this.data = data);
}
)
.catch(function(err) {
console.log('Fetch Error :-S', err);
});
}
render() {
<div>
$ {
(this.data || []).map(emp => emp.active ? this.dataTemplate(emp) : '')
}
</div>
}
}
customElements.define('emp-component', EmpComponent);
Upvotes: 1
Reputation: 3142
You're not returning anything in getEmpData()
so this.data
is undefined
, hence the error.
Keep in mind that if you add a return
statement before the fetch()
call this.data
will then contain a Promise
. The until
directive can help in this case:
import {until} from 'lit-html/directives/until.js';
// ...
render() {
return html`
<div>
${until(
this.data.then(data => data.map(emp => emp.active ? this.dataTemplate(emp) : ''),
html`<p>Loading...</p>`,
)}
</div>
`;
}
Upvotes: 1