Vue 3: Cannot read property 'id' of null - vuejs3

I want to show list product from api but it shows the error:
Uncaught (in promise) TypeError: Cannot read property 'id' of null
at eval (Home.vue?bb51:103)
at renderList (runtime-core.esm-bundler.js?5c40:6635)
at Proxy.render (Home.vue?bb51:2)
at renderComponentRoot (runtime-core.esm-bundler.js?5c40:1166)
at componentEffect (runtime-core.esm-bundler.js?5c40:5265)......
my product like :
[
{
"id": 1,
"name": "chair",
"categoryId": 12,
"unitId": 2,
"price": 66000000,
"salePrice": 0,
"material": "wood",
"size": "x"
},
]
My code here:
Home.vue file
<ProductCard v-for="product in products" :key="product.id" :product="product" />
ProductCard.vue file
<script>
export default {
name: "ProductCard",
props: {
product: {
type: Object,
required: true,
},
},
};
</script>
ProductService.js file
const apiClient = axios.create({
baseURL: 'http://localhost:8888/api/v1',
withCredentials: false,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
})
export default {
getProducts() {
return apiClient.get('/product/get-list-product-by-subcategory')
},
}
When I print out list product in console. It still work.
Does anyone know where is the bug in my code?
Updated:
I try to fix my bug "Cannot read property 'id' of null", Steve's answer although remove my red warning in devtool but not deal my data: my data still not showing up. And I find out my code work by using this.products = response.data.data
ProductService.getProducts()
.then((response) => (this.products = response.data.data))
.catch((error) => console.log("error: " + error));
Explain by myself is:
When console.log(this.products = response)
And I need to use this.products = response.data.data to enter to array

apiClient.get(...)
returns a promise not the actual data from the API call.
You need to add a then. like so
apiClient.get(...).then(response => (this.products = response))
Then when the apiClient.get completes this.products will be populated with the data from the API.

Try this
<ProductCard v-for="product in products" :key="product._id" :product="product" />

Related

Why doesn't my fetch POST function work in Svelte?

I have a Svelte application that is supposed to perform CRUD operations with a local JSON file via the Fetch API.
The "GET" operations works as intended but when I tried to create the "POST" function, I got the below error message:
Uncaught (in promise) Error: {#each} only iterates over array-like objects.
at validate_each_argument (index.mjs:1977)
at Object.update [as p] (index.svelte? [sm]:33)
at update (index.mjs:1057)
at flush (index.mjs:1025)
Below is the code in index.svelte:
<script>
import { onMount } from 'svelte';
let data1 = '';
onMount(async function () {
const data = await (await fetch('http://localhost:5000/data1')).json();
data1 = data;
console.log(data);
});
const createData1 = async () => {
const data =
(await fetch('http://localhost:5000/data1'),
{
method: 'Post',
body: JSON.stringify({
id: data1.length + 1,
text: '',
}),
headers: {
'Content-Type': 'application/json'
}
});
data1 = data;
console.log(data);
};
</script>
<div style="display: grid; place-items:center;">
<div class="horizontal">
{#each data1 as d1}
<div contenteditable="true">{d1.text}</div>
{/each}
<button type="submit" on:click|preventDefault={createData1}>+</button>
</div>
</div>
And below is the contents of the JSON file:
{
"data1": [
{
"id": 1,
"text": "blabla",
},
{
"id": 2,
"text": "bla bla",
}
]
}
Why isn't the the object being created? It is inside an array after all.
As your log shows, data is an object, not an array. data.captions is the array you want to iterate over.
So you'll want to slightly modify your createData method near the end:
const createData1 = async () => {
...
// data1 = data;
data1 = data.data1;
console.log(data);
};
It looks to me like you need to adjust your code syntax a bit and make sure you convert your response to JSON and you will be in business. This should work:
const data = (await fetch('http://localhost:5000/data1', {
method: "POST",
body: JSON.stringify({
id: data1.length + 1,
text: ''
}),
headers: {
"content-type": "application/json"
}
})).json();
data1 = data;
The notable adjustments are:
Use the fetch overload that takes first argument as URL and the second argument as the request options object (Looks like this is what you were after and an extra "(" character was throwing it of)
Make sure to convert the result of the POST call to JSON. Your "GET" request does this conversion and you get what you are expecting.

How to fix 'RealmObject cannot be called as a function' realm-js error?

In a react-native project using Realm-js, I've just created a clone of the app, integrated all libs, and copied over all src directories.
The app builds installs and runs on Android.
When i go through the authentication flow (which utilizes realm to store auth data), i ultimately get an error:
[ Error: RealmObject cannot be called as a function ]
login function:
async function login(username, password) {
try {
const result = await Api.login({
username: username,
pass: password,
});
const userAuthResult = await Db.updateAuth(result);
setUserAuth(userAuthResult);
} catch (err) {
console.log('[ ERROR ]:', err)
if (!err.message || err.message.includes('Network Error')) {
throw new Error('Connection error');
}
throw new Error('Wrong username or password');
}
}
and ive narrowed down the issue to Db.updateAuth(...)
updateAuth:
export const updateAuth = (params) => {
console.log(' [ HERE 1 ]')
const auth = {
id: params.id,
token: params.token,
refreshToken: params.refresh_token,
tokenExpiresAt: Math.floor(Date.now() / 1000) + 600, //params.expires_at,
federatedToken: params.federatedToken ?? '',
federatedTokenExpiresAt: params.federatedTokenExpiresAt ?? 0,
username: params.username,
name: params.name,
roleName: params.role_name,
roleId: params.role_id,
lastLogin: Math.floor(Date.now() / 1000),
};
console.log(' [ HERE 2 ]')
realm.write(() => {
console.log(' [ HERE 3 ]')
realm.create('Authorizations', auth, 'modified'); // PROBLEM
});
return auth;
};
inspecting the schema, i found theres no federatedToken propereties, yet in the auth update object, there are two. not sure why it wouldnt be throwing an error in the original non-cloned app.
authorizations schema:
AuthorizationsSchema.schema = {
name: 'Authorizations',
primaryKey: 'id',
properties: {
id: 'int',
token: 'string',
refreshToken: 'string',
tokenExpiresAt: 'int',
username: 'string',
name: 'string',
roleName: 'string',
roleId: 'int',
lastLogin: 'int',
},
};
Realm.js (class declaration) -> https://pastebin.pl/view/c903b2e2
from realm instantiation:
let realm = new Realm({
schema: [
schema.AccountSchema,
schema.AuthorizationsSchema,
schema.AvailableServiceSchema,
schema.FederatedTokensSchema,
schema.NoteSchema,
schema.PhotoSchema,
schema.PhotoUploadSchema,
schema.PrintQueueSchema,
schema.ProductSchema,
schema.ReportSchema,
schema.ServicesSchema,
schema.UploadQueueJobSchema,
schema.InvoicesSchema,
schema.TestSchema
],
schemaVersion: 60,
deleteRealmIfMigrationNeeded: true,
//path: './myrealm/data',
});
this logs the 1, 2, and 3 statements. The issue seems to come from the 'problem' line. Im not sure what exactly this error means, as there doesnt seem to be anything in realm's repo about it, and in the app this was cloned from, there was no issue with this line. I can also see other lines are throwing similar errors later on the user flows
Anyone know what this is about? or where i can learn more?
React-native: v64.2
realm-js: 10.6.0 (app cloned from was v10.2.0)
MacOS: 11.3 (M1 architecture)
in order to create you have the first call, the realm.write a method like this.
const storeInDataBase = (res,selectedfile) => {
try{
realm.write(() => {
var ID =
realm.objects(DocumentConverstionHistory).sorted('HistoryID', true).length > 0
? realm.objects(DocumentConverstionHistory).sorted('HistoryID', true)[0]
.HistoryID + 1
: 1;
realm.create(DocumentConverstionHistory, {
HistoryID: ID,
Name:`${selectedfile.displayname}.pdf`,
Uri:`file://${res.path()}`,
Date: `${new Date()}`
});
})
}catch(err){
alert(err.message)
}
}
Here is the schema file
export const DATABASENAME = 'documentconverter.realm';
export const DocumentConverstionHistory = "DocumentConverstionHistory"
export const DocumentConverstionHistorySchema = {
name: "DocumentConverstionHistory",
primaryKey: 'HistoryID',
properties: {
HistoryID: {type: 'int'},
Name: {type: 'string'},
Uri: {type: 'string?'},
Type: {type: 'string?'},
Size: {type: 'string?'},
Date: {type: 'date?'}
}
};

how to get JSON data in from firebase, and then use it in angular 6, firebase return the data with value tag

I am using firebase functions to get data from db, this is how I am doing it,
exports.getTopPlayers = (request,response)=> {
SavePlayers(function(data,err){
if(err) console.log(err);
response.header('Access-Control-Allow-Origin', '*');
response.header(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept'
);
const dbRef = admin.database().ref().child('topplayers/-LISMykRqLrVcc7xrK60');
dbRef.on('value', snap => {
var dbPlayer = snap.val();
response.send(dbPlayer);
});
});
Then I am using it in my website built in angular 6
getTopPlayers() {
return this.http.get(this.topPlayerURL);
}
It the be data in the below format,
{value: "[{"name":"WHYALWAYSME","tag":"9P08LYLL","rank":1,"…na":"League 8","arenaID":20,"trophyLimit":6100}}]"}
I want to get rid of this value tag. How can I? When I try to loop on this using
ngFor (*ngFor="let tp of topPlayer$) it return error, Cannot loop
[object,object]
I want the data in the below format,
[
{
name: "Leslie",
tag: "RPP89PVY",
rank: 1,
previousRank: 3,
expLevel: 13,
trophies: 6361,
donationsDelta: null,
clan: {
tag: "9CU2PQ2J",
name: "不正经的养老院",
badge: {
name: "Cherry_Blossom_04",
category: "01_Symbol",
id: 16000131,
image: "https://royaleapi.github.io/cr-api-assets/badges/Cherry_Blossom_04.png"
}
},
arena: {
name: "Grand Champion",
arena: "League 8",
arenaID: 20,
trophyLimit: 6100
}
},
I found the solution,
In angular in component init method, I did the following,
Call the service and read the data in a string array,
topPlayer$: string[];
ngOnInit() {
this.topPlayerSrvice.getTopPlayers()
.subscribe(response => {
let topPlayer: string[];
topPlayer = response.json();
this.topPlayer$ = JSON.parse(topPlayer['value']);
});
}

Angular2 - http call Code coverage

My components.ts is,
getHomePageData() : void{
this.homeservice.getHomePageData()
.subscribe(
data => {
//console.log("response status ################### "+data.status);
//console.log("getUserData response ************ \n"+JSON.stringify(data));
this.defaultFacilityId = data.response.defaultFacilityId;
this.defaultFacilityName = data.response.defaultFacilityName;
this.enterpriseId = data.response.enterpriseId;
this.enterpriseName = data.response.enterpriseName;
this.facilityList = data.response.facilityList;
this.userName = data.response.userName;
this.showDefaultPopoup();
},
error => {
console.error(error);
//this.errorMessage="Technical error - Contact Support team !" ;
}
);
}
So my component.spec.ts is ,
it('getHomePageData with SUCCESS - getHomePageData()', () => {
backend.connections.subscribe((connection: MockConnection) => {
//expect(connection.request.url).toEqual('http://localhost:8080/MSMTestWebApp/UDM/UdmService/Home/');
expect(connection.request.url).toEqual('http://192.168.61.158:9080/GetUserData');
expect(connection.request.method).toEqual(RequestMethod.Get);
expect(connection.request.headers.get('Content-Type')).toEqual('application/json');
let options = new ResponseOptions({
body:
{
"request": { "url": "/getUserData" },
"response": {
"defaultFacilityName":"3M Health Information Systems",
"enterpriseId":"11.0",
"enterpriseName":"HSA Enterprise",
"defaultFacilityId": "55303.0",
"userName":"Anand"
},
"error": ""
},
status : 200
});
connection.mockRespond(new Response(options));
});
backend.connections.subscribe((data) => {
//expect(data.response.facilityId).toEqual("55303.0");
//expect(subject.handleError).toHaveBeenCalled();
})
service.getHomePageData().subscribe((data) => {
//expect(videos.length).toBe(4);
expect(data.response.defaultFacilityId).toEqual("55303.0");
component.defaultFacilityId = data.response.defaultFacilityId;
component.defaultFacilityName = data.response.defaultFacilityName;
component.enterpriseId = data.response.enterpriseId;
component.enterpriseName = data.response.enterpriseName;
component.userName = data.response.userName;
console.log("$$$$$$$$$$$$$$$$**********$$$$$$$$$$$$$$$$$$$$$");
});
});
When i try to run test case. It got passed. But while I look into the code coverage, it doesn't cover the code shown in red below
Please help to get the full code coverage. Thanks.
In the test you've shown here you don't seem to be calling getHomePageData() from your component
Try building your test like this:
import { fakeAsync, tick } from '#angular/core/testing';
...
it('getHomePageData with SUCCESS - getHomePageData()', fakeAsync(() => {
backend.connections.subscribe((connection: MockConnection) => {
//expect(connection.request.url).toEqual('http://localhost:8080/MSMTestWebApp/UDM/UdmService/Home/');
expect(connection.request.url).toEqual('http://192.168.61.158:9080/GetUserData');
expect(connection.request.method).toEqual(RequestMethod.Get);
expect(connection.request.headers.get('Content-Type')).toEqual('application/json');
let options = new ResponseOptions({
body:
{
"request": { "url": "/getUserData" },
"response": {
"defaultFacilityName":"3M Health Information Systems",
"enterpriseId":"11.0",
"enterpriseName":"HSA Enterprise",
"defaultFacilityId": "55303.0",
"userName":"Anand"
},
"error": ""
},
status : 200
});
connection.mockRespond(new Response(options));
});
// If this function is not automatically called in the component initialisation
component.getHomePageData();
tick();
//you can call expects on your component's properties now
expect(component.defaultFacilityId).toEqual("55303.0");
});
FakeAsync allows you to write tests in a more linear style so you no longer have to subscribe to the service function to write your expectations.
In a FakeAsync test function you can call tick() after a call where an asynchronous operation takes place to simulate a passage of time and then continue with the flow of your code.
You can read more about this here: https://angular.io/docs/ts/latest/testing/#!#fake-async
EDIT - Error Case
To test the error logic you can call mockError or set up an error response using mockRespond on your connection:
it('getHomePageData with ERROR- getHomePageData()', fakeAsync(() => {
backend.connections.subscribe((connection: MockConnection) => {
if (connection.request.url === 'http://192.168.61.158:9080/GetUserData') {
// mockError option
connection.mockError(new Error('Some error'));
// mockRespond option
connection.mockRespond(new Response(new ResponseOptions({
status: 404,
statusText: 'URL not Found',
})));
}
component.getHomePageData();
tick();
//you can call expects now
expect(connection.request.url).toEqual('http://192.168.61.158:9080/GetUserData');
expect(connection.request.method).toEqual(RequestMethod.Get);
expect(connection.request.headers.get('Content-Type')).toEqual('application/json');
expect('you can test your error logic here');
});
What we're doing inside the subscription is making sure that anytime the GetUserData endpoint is called within this test method it will return an error.
Because we test errors and successes separately in the success test there's no need to add the error related settings in the request options.
Are you using JSON data? Then you should probably use map() before using .subscribe().
.map((res:Response) => res.json())
Try organizing your code like this:
ngOnInit() {
this.getHomePageData();
}
getHomePageData() {
this.http.get('your.json')
.map((res:Response) => res.json())
.subscribe(
data => {
this.YourData = data
},
err => console.error(err),
() => console.log('ok')
);
}
Hope it helps,
Cheers

dgrid JsonRest store not working

I have the following:
require([
"dojo/dom",
"dojo/on",
"dojo/store/Observable",
"dojo/store/JsonRest",
"dojo/store/Memory",
"dgrid/OnDemandGrid"
], function (dom, on, Observable, JsonRest, Memory, OnDemandGrid) {
var store = new JsonRest({
target: 'client/list',
idProperty: 'id'
});
var grid = new OnDemandGrid({
columns: {
"id": "ID",
"number": "Name",
"description": "Description"
},
sort: "lastName",
store: store
}, "grid");
});
client/list is a rest url returning a json object {data:[...]}, but the content of the list never shows up :/
I think the problem is caused by the async data loading, because with a json hard coded object the content show up
EDIT :
I've succeeded in achieving this by using a dojo/request, but the JsonRest shouldn't normally act the same way ? Can someone point me to the right direction ?
require([
'dojo/dom',
'dojo/on',
'dojo/store/Memory',
'dojo/request',
'dgrid/OnDemandGrid'
], function (dom, on, Memory, request, OnDemandGrid) {
request('client/list', {
handleAs: 'json'
}).then(function (response) {
// Once the response is received, build an in-memory store with the data
var store = new Memory({ data: response });
// Create an instance of OnDemandGrid referencing the store
var grid = new OnDemandGrid({
store: store,
sort: 'id', // Initialize sort on id, ascending
columns: {
'id': 'ID',
'number': 'Name',
'description': 'Description'
}
}, 'grid');
console.log(store);
on(dom.byId('queryForm'), 'input', function (event) {
event.preventDefault();
grid.set('query', {
// Pass a RegExp to Memory's SimpleQueryEngine
// Note: this code does not go out of its way to escape
// characters that have special meaning in RegExps
description: new RegExp(this.elements.last.value, 'i')
});
});
on(dom.byId('queryForm'), 'reset', function () {
// Reset the query when the form is reset
grid.set('query', {});
});
});
});
Ok problem found :/
My "client/list" url was returning a json object like this:
{data: [{id:"1", label: "test"}, {id:"2", label: "test"}]}
Turns out that the JsonRest object is already encapsulating data in a data node, so by returning a json like this:
{[{id:"1", label: "test"}, {id:"2", label: "test"}]}
everything worked fine :)

Resources