EmberJS Cannot set property 'store' of undefined (DS.hasMany) - javascript

Firstly I have read the related issues on SO and none seem to help me.
I have 2 models, Foo and Bar. Foo has a property, bars, which hasMany Bar.
// FOO
export default DS.Model.extend({
name: attr('string'),
bars: hasMany('bar')
});
// BAR
export default DS.Model.extend({
name: attr('string')
foo: belongsTo('foo')
});
And the JSON payload:
{
"name": "Something",
"bars": [
{
"name": "something else"
},
{
"name": "another one"
}
]
}
I've been trying to figure this error out for a while but I am stuck.
Here is the jsbin.
If you look in the browsers console (not the jsbin one) you can see the error.

It looks like you are not specifying an ID for your "bar" objects. Each model needs an ID to make the object unque and know how to relate that to a resource. Changing your server output to the following should solve the issue:
{
"name": "Something",
"bars": [
{
"id": 1,
"name": "something else"
},
{
"id": 2,
"name": "another one"
}
]
}
Another solution (IDs should really be there regardless) is to set "async" to true as follows:
export default DS.Model.extend({
name: attr('string'),
bars: hasMany('bar', { async: true })
});
This will cause EmberJS to load the data in the background and not block/causes errors with anything waiting on relationship resoltion.

Related

Add new child objects to existing object in React

I am trying to update through useState a child object with an additional object. I created an example to make this more clear :
https://codesandbox.io/s/affectionate-wescoff-u01x0?file=/src/App.js
The example object looks like :
{
"id": 123,
"books": {
"book": {}
}
}
When I push more data in I want it to look like this :
{
"id": 123,
"books": {
"book": {
"name": "Sirens of Titan",
"author": "Kurt Vonnegut"
},
"book": {
"name": "The Hobbit",
"author": "J.R.R. Tolkein"
}
}
}
At this stage I have it pretty messed up and it looks like :
{
"id":123,
"books":[
{
"0":{
"book":{
},
"sampleData1":{
"book":{
"name":"Sirens of Titan",
"author":"Kurt Vonnegut"
}
}
},
"sampleData2":{
"book":{
"name":"The Hobbit",
"author":"J.R.R. Tolkein"
}
}
}
]
}
This is the way I set that broken object :
const [main, setMain] = useState(library);
function addNestedObj() {
setMain({ ...main, books: [{ ...main.books, sampleData1 }] });
}
Just take the destructuring a stage further:
setMain({...main, kids: [...main.kids, secondObj]})
The books property of your library object was an object, not an array. This might have been necessary but I guessed that it isn't since your book objects already have a name property, so they don't need a separate key.
With that change, you can modify your setMain function to add the book property of the sampleData to the books property of your state:
setMain({ ...main, books: [...main.books, sampleData1.book] });
I've added these changes in a fork of your CodeSandbox: https://codesandbox.io/s/modest-fog-byegh?file=/src/App.js

Unable to read objectValue data using "level" query

According to the smartsheet API Docs, I should be able to use "level" parameter in my options to get a complex object for Multi-Contact columns.
Unfortunately all I'm getting in return is value and displayValue.
Am I doing something wrong here?
var options = {
id: SHEET_ID, //Id of sheet
queryParameters = {
include: ["objectValue"],
level: 1
}
}
ss.sheets.getSheet(options)
.then(function (results) {
console.log(results.rows[args[0]].cells[6])
})
The above code returns:
{ columnId: 8746190272522116, displayValue: 'John Smith, Danny Doe' }
I've verified (using Postman) that Smartsheet API does indeed support the scenario you've described. i.e., if I submit this Get Sheet request:
https://api.smartsheet.com/2.0/sheets/5831916227192708?include=objectValue&level=1
...then the response does include the complex object for a multi-contact cell in my sheet:
{
"id": 5831916227192708,
...
"rows": [
{
"id": 5942480978372484,
...
"cells": [
{
"columnId": 3992195570132868,
"objectValue": {
"objectType": "MULTI_CONTACT",
"values": [
{
"objectType": "CONTACT",
"email": "john_doe#test.com",
"name": "John Doe"
},
{
"objectType": "CONTACT",
"email": "jane_doe#test.com",
"name": "Jane Doe"
}
]
},
"displayValue": "John Doe, Jane Doe"
},
...
]
},
...
]
}
However, it looks like the Smartsheet JavaScript SDK doesn't yet support this scenario.
It's not unusual for SDK updates to lag a bit behind the release of new API features. You might consider logging an issue in the JavaScript SDK repo to request that support for this scenario be added -- or better yet, submit a PR to that repo that adds support for this scenario. In the meantime, you'll need to implement this functionality yourself within your integration (i.e., since you can't rely on the out-of-the-box SDK functionality to provide it at this time).
You just need to remove the array notations from your options definition:
var options = {
id: SHEET_ID, //Id of sheet
queryParameters = {
include: "objectValue",
level: 1
}
}
ss.sheets.getSheet(options)
.then(function (results) {
console.log(results.rows[args[0]].cells[6])
})

Vue js - reference variable in object

I am new to vue and can't find a solution to this -
I have a JSON object here, and I am trying to dynamically fetch the "info" of a user based on their "userRegion".
{
"userData": {
"kr": {
"info": {
"name": "testing-123",
}
},
"any": null,
"us": null,
"eu": {
"info": {
"name": "testing-456",
}
},
},
"userRegion": "eu"
}
I then have this object in vue and I want to dynamically change region and pull the data from the object based on this region value in the "user" object below.
user:{
region: this.userData.userRegion,
name: this.userData[this.user.region].info.name
},
For example, I have tried using something like this
this.userData.userData[this.user.region]
but I get an error:
TypeError: Cannot read property 'region' of undefined"
the variable I am using "userData" is passed down from the parent like so:
<infoWindow :userData='userData'></infoWindow>
and is set as a prop:
props: {
userData: app.userData,
},
any help would be aprpeciated, thanks
I don’t really understand where you are setting this user, whether its part of an initialized data object, or a computed property. However, there is a temporal issue there:
user: {
region: this.userData.userRegion,
name: this.userData[this.user.region].info.name
},
In order to set up user.name, user.region needs to be already there. But since you are creating the user object at once, this does not work. So you either have to split that up, or repeat the logic for the user region again:
user: {
region: this.userData.userRegion,
name: this.userData[this.userData.userRegion].info.name
},

Ember.js findRecord() called with id null for model with alternative primary key

I have an issue with my Ember.js application. It uses the JSONAPI{Adapter,Serializer} and the following model:
models/node.js
App.Node = DS.Model.extend(
{
// (node 'name' field used as primary key for serialization)
info: DS.attr('string'),
children: DS.hasMany('node', { inverse: null })
}
Which represents a tree of named nodes.
The JSONAPIAdapter (adapters/application.js) implements the functions queryRecord(), query(), findRecord(), findAll() to translate the Ember.js queries from the server. This all works fine.
The JSONAPISerializer implements the function normalizeResponse() to translate the server response JSON data to json:api format. In the serializer, the primary key is defined to be the 'name' field of the node:
serializers/application.js
App.ApplicationSerializer = DS.JSONAPISerializer.extend(
{
primaryKey: 'name',
normalizeResponse(store, primaryModelClass, payload, id, requestType)
{
// ...
}
});
A sample of the json:api data generated by the serializer is:
{
"data": [
{
"type": "node",
"attributes": {
"info": "Root node"
},
"relationships": {
"children": {
"data": [
{
"type": "node",
"name": "Root/SubNode1"
}
]
}
},
"name": "Root"
}
],
"included": [
{
"type": "node",
"attributes": {
"info": "Subnode 1"
},
"relationships": {
"children": {
"data": [
]
}
},
"name": "Root/SubNode1"
}
]
}
I use Ember.js version 2.7.0 and Ember inspector.
Once the application is running, and data is loaded in the model, I can see the data in Ember inspector being visible in the model. However, when investigating the model data in the 'Data' view (and selecting an item), I find that Ember is invoking adapter:findRecord() with id = null, resulting in an erroneous query. Somehow it seems the model data is incorrect.
When I remove the primary key definition in the JSONAPISerializer and duplicate the name field of a node in the id field as the Ember default primary key, all is fine. What am I missing with my primary key definition? The Ember guide only states information about the primaryKey in the serializer (https://guides.emberjs.com/v2.7.0/models/customizing-serializers/#toc_ids).
Many thanks in advance!
You need to define name field to have a place to save the id.
App.Node = DS.Model.extend(
{
// (node 'name' field used as primary key for serialization)
name: DS.attr('string'),
info: DS.attr('string'),
children: DS.hasMany('node', { inverse: null })
}

Ember.js get nested resources attributes from parent

I have these models:
TravelClient.Tour = DS.Model.extend({
title: DS.attr('string'),
description: DS.attr('string'),
seats: DS.attr('number'),
takenSeats: DS.hasMany('TravelClient.TakenSeat', {embedded:'always'})
TakenSeats: function() {
console.log(this.get('takenSeats').toArray())
}.property('takenSeats')
});
TravelClient.TakenSeat = DS.Model.extend({
tour: DS.belongsTo('TravelClient.Tour'),
number: DS.attr('number')
});
JSON looks like this:
{
"tours": [
{
"id": "5110e8b5a8fefe71e0000197",
"title": "qui deserunt dolores",
"description": "Id velit nihil.",
"seats": 12,
"taken_seats": [
{
"id": "5110e8b5a8fefe71e0000196",
"number": "5"
},
{
"id": "5110e8b5a8feffffe0000196",
"number": "2"
}]
}
But yeah, when I do console.log(this.get('takenSeats').toArray() in Tour model's method, it returns Uncaught TypeError: Cannot call method '_create' of undefined, so, it seems that takenSeats did not load with parent model. What's wrong?
UPDATE
added tour_id to JSON, but now, when I want to use calculated property:
freeSeats: function() {
var seats = this.get('seats');
var takenSeats = this.get('takenSeats');
if (takenSeats) {
return (seats - takenSeats.length);
}
else {
return seats;
}
}.property('seats', 'takenSeats')
takenSeats is undefined.
UPDATE 2:
TravelClient.RESTSerializer = DS.RESTSerializer.extend({
init: function() {
this._super();
this.map('TravelClient.Tour',{
images:{embedded:'always'},
options:{embedded:'always'},
takenSeats:{embedded:'always'}
});
}
});
TravelClient.CUSTOMAdapter = DS.RESTAdapter.extend({
bulkCommit: false,
serializer: TravelClient.RESTSerializer.create(),
url: "http://192.168.1.27:3000",
buildURL: function(record, suffix) {
var s = this._super(record, suffix);
return s + ".json";
}
});
TravelClient.Store = DS.Store.extend({
revision: 11,
adapter: TravelClient.CUSTOMAdapter.create()
});
TravelClient.store = TravelClient.Store.create();
the TakenSeats computed property is perceived as a class because it's capitalized. Next to that embedded loading has to configured differently. Like so: This way the tour object becomes dirty when a takenseat changes.
DS.RESTAdapter.map('TravelClient.Tour', {
takenSeats: { embedded: 'always' },
});
Or: This way the tour doesn't become dirty.
DS.RESTAdapter.map('TravelClient.Tour', {
takenSeats: { embedded: 'load' },
});
Do this before you initialize your Store and Adapter. This will make the computed property unnecessary. You can just do tour.get('takenSeats');
Oh and you don't have to specify that the type is embedded anymore. The id's in the taken_seats array that link back to the tour need to be called tour_id.
{
"tours": [{
"id": "5110e8b5a8fefe71e0000197",
"taken_seats": [{
"id": "5110e8b5a8fefe71e0000196",
"tour_id": "5110e8b5a8fefe71e0000197"
"number": "5"
}]
}]
}
I had a similar problem to this. ember-model doesn't map through nested objects.
Your JSON output currently has all the data nested beneath the tours root.
If you have access to the API, then i suggest trying to remove the root, otherwise look into using your as the main object and then grabbing all the nested objects from there on down.
instead of this:
"tours": [{
"id": "5110e8b5a8fefe71e0000197",
"taken_seats": [{
"id": "5110e8b5a8fefe71e0000196",
"tour_id": "5110e8b5a8fefe71e0000197"
"number": "5"
}]
}]
make it look like this:
[{
"id": "5110e8b5a8fefe71e0000197",
"taken_seats": [{
"id": "5110e8b5a8fefe71e0000196",
"tour_id": "5110e8b5a8fefe71e0000197"
"number": "5"
}]
}]
its possible my syntax is off, but this similar idea worked for me.

Categories

Resources