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.
Related
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
I'm using Typescript with TypeORM. Using CreateQueryBuilder, I want to receive a nested object. Instead I'm receiving a single flat object as represented in block number two. How can I fix this?
const x = await getConnection()
.createQueryBuilder()
.select(['reportHead', 'order', 'workOrder'])
.from('report_head', 'reportHead')
.innerJoin('reportHead.workOrder', 'workOrder')
.innerJoin('workOrder.order', 'order')
.where(`order.customer.id = :customerId`, { customerId: req.user.customer.id })
.execute();
How can I avoid the data looking like this:
{
"reportHead_id": "asd",
"reportHead_number": "123",
"workOrder_id": "dsa",
"workOrder_status: "OK",
"order_id": "sda",
"order_whatev": "ks"
}
but rather have a neste object like this:
{
"reportHead": {
"id": ...
},
"workOrder": {
"id": ...
},
"order": {
"id": ...
}
}
The solution was to not use .execute(), but rather .getMany().
I'm very new to angularjs and need some advice about the angular way to implement something very simple. In my $scope I need to set some field defaults, and these defaults are needed multiple times in my controller.
I want to be able to refactor these defaults out to a common place, to thin out the controller and allow for code reuse, but not sure if this should be a factory, directive or service.
Heres an example of the defaults:
$scope.skills = [{
description: '',
years: "1",
level: "0",
years_values: [
{ id: "1", description: "1" },
{ id: "2", description: "2" },
{ id: "3", description: "3+" }],
level_values: [
{ id: "0", description: "Starter"},
{ id: "1", description: "Intermediate"},
{ id: "2", description: "Advanced"} ]
}]
Here's an example of where I'd like to call the "new function":
skillSuccess = (resp)->
Loader.hide();
$rootScope.current_user = resp;
#TODO replace this repetition
$scope.skills = [{
description: '',
.... etc
My questions are:
Should I use a factory/directive/service, (or something else) for
this refactoring?
How do I ensure that the function gets called
initially so that the default values are available for the fields
when the page loads?
Should I use a factory/directive/service, (or something else) for this
refactoring?
I'd suggest you to create a constant because looks like you have defaults data which has initially has some value and that will going to be change by the user from the front-end. So you could place that in angular constant, then that constant will be accessed by the factory/service. And Factory/service will do the needful manipulation from its function. To make available constant in your service/factory you need to inject constant name in your service.
By looking at your current requirement you shouldn't be take consideration of directive component.
Constant
app.constant('defaults', [{
description: '',
years: "1",
level: "0",
years_values: [
{ id: "1", description: "1" },
{ id: "2", description: "2" },
{ id: "3", description: "3+" }],
level_values: [
{ id: "0", description: "Starter"},
{ id: "1", description: "Intermediate"},
{ id: "2", description: "Advanced"} ]
}]);
Service
app.service('dataService', function(defaults){
var dataService = this;
dataService.defaults = defaults;
dataService.defaults = angular.copy(defaults) //will return same copy every-time
dataService.getDefaults = function(){
return dataService.defaults;
}
//other method will lie here
})
How do I ensure that the function gets called initially so that the default values are available for the fields when the page loads?
You could simply get that defaults by consuming getDefaults method of your service, then stored that retrieved defaults and use those for manipulation.
If you want the defaults copy to instantiated every-time then use angular.copy(defaults) which will give you the copy of defaults.
Controller
app.controller('myCtrl', function($scope, dataService){
$scope.defaults = dataService.getDefaults(); //this will have defaults
//...other stuff here...
});
Should I use a factory/directive/service, (or something else) for this refactoring?
A controller should be used to set the scope, but the default values should be stored as a constant and returned by a factory. A factory pattern is preferred here because it is a singleton.
angular.module('myApp')
.factory('skillsFactory', function (defaultSkills) {
var service = {};
service.getDefaults = function () {
return defaultSkills;
};
return service;
})
.constant('defaultSkills', [{
description: '',
years: "1",
level: "0",
years_values: [{
id: "1",
description: "1"
}, {
id: "2",
description: "2"
}, {
id: "3",
description: "3+"
}],
level_values: [{
id: "0",
description: "Starter"
}, {
id: "1",
description: "Intermediate"
}, {
id: "2",
description: "Advanced"
}]
}]);
How do I ensure that the function gets called initially so that the default values are available for the fields when the page loads?
In your controller, call $scope.skills = skillsFactory.getDefaults();
angular.module('myApp')
.controller('skillsCtrl', function ($scope, skillsFactory) {
$scope.skills = skillsFactory.getDefaults();
});
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.
I am trying to add this list into my view model in order to make some bindings a little bit simpler. However, I can't figure out the syntax in order to do so.
var images = [
{ name: "Image 1", photo: "/images/image1.jpg" },
{ name: "Image 2", photo: "/images/image2.jpg" },
{ name: "Image 3", photo: "/images/image3.jpg" },
];
var viewModel = {
favorite: "",
...
}
Assign images to viewModel like this:
var viewModel = {
favorite: "",
images: images
};
Then access them like this viewModel.images