I'm having trouble getting Ember's queryRecord to work properly. I'm trying to grab a site config from the server.
//app/routes/application.js
model: function(){
return this.get('store').queryRecord('config',{}).then(function(config) {
console.log(config.get('appname'));
});
}
//app/adapters/config.js
import DS from "ember-data";
import ENV from './../config/environment';
export default DS.Adapter.extend({
queryRecord(modelName, query) {
return Ember.$.getJSON( ENV.APP.apiFull + 'config' );
}
});
//app/serializers/applications.js
import DS from 'ember-data';
export default DS.RESTSerializer.extend({
keyForAttribute: function(attr, method) {
return Ember.String.underscore(attr).toUpperCase();
}
});
//JSON returning from server AJAX call
{"config":{"id":1,"environment": "development", "appname":"Sample App Name"}}
The console.log statement in //app/routes/application is returning undefined. This all seems to match up with the Ember documentation for version 2.9. What am I doing incorrectly?
#Lux, thanks for pointing me towards the serializer. That led to me looking at the model member names and I found that I had underscored them in the model, but not in the JSON coming from the server.
Related
I'm building a custom API, with an endpoint defined as follow:
I have a created a Profiling Controller to handle the logic for this endpoint. My controller directory contains 2 files:
controller.ts
import { Request, Response } from 'express';
import ProfilingService from '../../services/profiling.service';
export class Controller {
enrich_profile(req: Request, res: Response): void {
console.log(req);
ProfilingService.enrich_profile(req).then((r) =>
res
.status(201)
.location(`/api/v1/profile_data/enrich_profile/data${r}`)
.json(r)
);
}
}
export default new Controller();
routes.ts
/* eslint-disable prettier/prettier */
import express from 'express';
import controller from './controller';
export default express.
Router()
.post('/enrich_profile', controller.enrich_profile)
;
However, when I sent a call to the endpoint, I get the following error:
And finally, to allow a full picture, here's the content of profiling.service.ts:
import L from '../../common/logger';
interface Profiling {
data: never;
}
export class ProfilingService {
enrich_profile(data: never): Promise<Profiling> {
console.log(data);
L.info(`update user profile using \'${data}\'`);
const profile_data: Profiling = {
data,
};
return Promise.resolve(profile_data);
}
}
export default new ProfilingService();
The error clearly states that POST to the defined endpoint is not possible, and I'm not sure I understand why.
How can I fix this issue?
I'm not sure what was causing the issue, but after cleaning my npm cache, and deleting node_modules about 100X, the issue finally went away.
UPDATE:
Can anyone help? I have been pursuing this without luck for the better half of this week. I do notice that the client is generating two POSTs. I have added code for the adapter. Is there anywhere else I should be looking?
I am going through the video tutorial provided below and am unable to resolve two errors when I click the submit button to save data to the database.
No model was found for 'user'
Two POSTs are being generated. This results in an Assertion Failed error, which I suspect is because the ID returned from the server does not match the current ID on the front-end.
I see that the database has two new records. When I click on the submit button again then the application takes me back to the todo-items page where it shows the two records. Can anyone advise what I am doing wrong?
Current versions:
Ember : 3.2.2
Ember Data : 3.2.0
jQuery : 3.3.1
Ember Simple Auth : 1.7.0
Video tutorial (the error occurs at the 11:30 mark): https://www.youtube.com/watch?v=bZ1D_aYGJnU. Note: the author of the video seems to have gotten the duplicate POST issue to go away right at the end of the video, but I do not see how.
Component/forms/todo-item-form/component.js
import Component from '#ember/component';
export default Component.extend({
actions:{
save(){
this.get('submit')();
}
}
});
Component/forms/todo-item-form/template.hbs
<form {{action "save" on="submit"}}>
{{input placeholder="description" value=todoItem.description}}
<br />
{{#if todoItem.validations.isValid}}
<button type="submit">Add</button>
{{else}}
<button type="submit" disabled>Add</button>
{{/if}}
</form>
templates/s/todo-items/add.hbs
{{forms/todo-item-form
todoItem=model
submit=(route-action "submitAction")
}}
{{outlet}}
models/todo-item.js
import DS from 'ember-data';
import { validator, buildValidations } from 'ember-cp-validations';
const { attr, belongsTo } = DS;
const Validations = buildValidations({
description: [
validator('presence', true),
validator('length', {
min: 4
})
]
});
export default DS.Model.extend(Validations, {
description: attr('string'),
owner: belongsTo('person')
});
adapter/Application.js
import DS from 'ember-data';
import ENV from 'todo-list-client/config/environment';
const {computed, inject :{service} } = Ember;
export default DS.JSONAPIAdapter.extend({
session: service(),
namespace: ENV.APP.namespace,
host: ENV.APP.host,
headers: computed('session.data.authenticated.token', function() {
let token = this.get('session.data.authenticated.access_token');
return { Authorization: `Bearer ${token}` };
}),
})
routes/s/todo-items/add.js
import Route from '#ember/routing/route';
export default Route.extend({
model(){
return this.store.createRecord('todo-item');
},
actions: {
submitAction() {
this.get('controller.model')
.save()
.then(() => {
this.transitionTo('s.todo-items');
});
}
},
});
The author adds Ember-Data-Route at about 15m5s for the add.js route as a mixin. This cleans up after the model.
He starts the explanation at that point, adds it in over the next minute or two in the video:
https://youtu.be/bZ1D_aYGJnU?t=15m5s
import Ember from 'ember';
import DataRoute from 'ember-data-route';
export default Ember.Route.extend(DataRoute, {
model() {
return this.store.createRecord('todo-item');
},
actions: {
save() {
this.get('controller.model')
.save()
.then(() => {
this.transitionTo('s.todo-items');
});
}
},
});
I'm trying to get brands items from my REST API with ember; but my API response does not match with ember-data expected. for example:
My model:
import DS from 'ember-data';
export default DS.Model.extend({
name: DS.attr('string'),
isActive: DS.attr('boolean')
});
My API url: http://localhost:3000/api/brands
its response with:
{"success":true,
"data":[
{"id":1,"name":"Mine","isActive":true,"createdAt":"2017-04-23T20:36:49.000Z","updatedAt":"2017-04-23T20:44:32.000Z"},
{"id":2,"name":"forever","isActive":true,"createdAt":"2017-04-23T20:41:14.000Z","updatedAt":"2017-04-23T20:43:57.000Z"}
]
}
but, Ember is expecting some like this:
"brands": [{
"id": 1,
"name": "foo",
"isActive": "foo"
}]
I'm trying to change the root json node in serializer called brand.js, but I can not make it work. :(
here my serializer/brand.js
import DS from 'ember-data';
export default DS.RESTSerializer.extend({
});
and my adapters/application.js
import DS from 'ember-data';
import DataAdapterMixin from 'ember-simple-auth/mixins/data-adapter-mixin';
import config from '../config/environment';
export default DS.RESTAdapter.extend(DataAdapterMixin, {
host: `${config.host}`,
namespace: `${config.namespace}`,
authorizer: 'authorizer:custom'
});
on browser console this message appears:
WARNING: Encountered "success" in payload, but no model was found for model name "success" (resolved model name using vanely-web#serializer:brand:.modelNameFromPayloadKey("success"))
WARNING: Encountered "data" in payload, but no model was found for model name "datum" (resolved model name using vanely-web#serializer:brand:.modelNameFromPayloadKey("data"))
How can I say to ember where the correct data is?.Some help is appreciated.
Sorry if my English is not well.
As you already did, you can override the RESTSerializer for every model.
What you want to achieve is response normalization. You can normalize your response by overriding normalizeResponse in your serializer (see the docs):
import Ember from 'ember';
import DS from 'ember-data';
const {
RESTSerializer
} = DS;
const {
get
} = Ember;
export default RESTSerializer.extend({
normalizeResponse(store, primaryModelClass, payload, id, requestType) {
// Only do normalization for reading:
if(requestType !== 'createRecord' && requestType !== 'updateRecord' && requestType !== 'deleteRecord') {
// Do your normalization here. For example (not tested):
payload = {
brands: get(payload, 'data')
};
}
return this._super(store, primaryModelClass, payload, id, requestType);
}
});
Instead of overriding normalizeResponse, you could also override the other normalization methods.
I've been successfully calling Meteor methods until I created a new Mongo collection. Both collections are found under /imports/collections/, so I know it's available to both client and server.
Here is the Meteor.method, which is pretty much the same as my working collection.:
import { Mongo } from 'meteor/mongo';
Meteor.methods({
'messages.insert': function(data) {
return Messages.insert({
otherCollectionId: data.otherCollectionId,
type: data.type,
createdAt: new Date(),
sender: this.userId,
text: data.text
});
}
});
export const Messages = new Mongo.Collection('messages');
Here's how I call it:
import React from 'react';
import { Messages } from '../../imports/collections/messages';
// other imports
export default class Chat extends React.Component {
// other code
handleComposeClick() {
if (this.refs.text) {
let data = {
playlistId: this.props.playlist._id,
type: 'user',
text: this.refs.text.value
};
Meteor.call('messages.insert', data, (error, playlistId) => {
if (!error) {
this.setState({error: ''});
this.refs.text.value = '';
} else {
this.setState({ error });
console.log(error);
}
});
}
}
// render()
}
Whenever I click and trigger handleComposeClick(), I get this error:
errorClass {error: 404, reason: "Method 'messages.insert' not found", details: undefined, message: "Method 'messages.insert' not found [404]", errorType: "Meteor.Error"}
Remember that anything inside the /imports folder will not work unless it's actually imported, either with this syntax:
import somethingINeed from '/imports/wherever/stuff';
import { somethingElseINeed } from '/imports/wherever/things';
or:
import '/imports/server/stuff';
So for methods, you may want to set up a structure where you have the following:
/lib/main.js
import '../imports/startup/lib';
/imports/startup/lib/index.js
import './methods';
// any other shared code you need to import
/imports/startup/lib/methods.js
import { Meteor } from 'meteor/meteor';
import { Messages } from '/imports/collections/messages'; // don't define your collections in a methods file
Meteor.methods({
'messages.insert': function(data) {
return Messages.insert({
otherCollectionId: data.otherCollectionId,
type: data.type,
createdAt: new Date(),
sender: this.userId,
text: data.text
});
}
});
Though if I were you, I'd use validated methods, where you actually import the method you want to use in order to use it, e.g.:
import { messagesInsert } from '/imports/common-methods/message-methods';
// code...
messagesInsert.call({ arg1, arg2 }, (error, result) => { /*...*/ });
With this structure, you would instead have /server/main.js import ../imports/startup/server which would import ./methods, which (in my particular project) looks like this:
// All methods have to be imported here, so they exist on the server
import '../../common-methods/attachment-methods';
import '../../common-methods/comment-methods';
import '../../common-methods/tag-methods';
import '../../common-methods/notification-methods';
import '../../features/Admin/methods/index';
import '../../features/Insights/methods';
import '../../features/Messages/methods';
Keep in mind, this doesn't actually execute the methods, it just makes sure they're defined on the server, so that when you import these validated methods on the client side and run them, it doesn't bomb out saying the method can't be found on the server side.
Import 'Messages' in your server side (/server/main.js)
Shout out to #MasterAM for helping me find my typo. Turns out I just had an incorrect path in /server/main.js
I'm kind of new to Ember and I'm on something that should be quite simple. Just trying to validate a form actually.
Using ember-forms and ember-validations.
Here is the part of the structure, I'll be quite exhaustive so you can get to the point but there is really not a lot of code:
/app
/controllers
/admin
/create-user.js
/models
/admin
/create-user.js
/routes
/admin
/create-user.js
/templates
/admin
/create-user.js
First, I'm not sure it's the good structure, especially about the model.
The model:
import DS from 'ember-data';
import EmberValidations from 'ember-validations';
export default DS.Model.extend(EmberValidations, {
entity: DS.attr()
}).reopen({
validations: {
entity: {
presence: true,
length: { minimum: 5 }
}
}
});
The controller:
import Ember from 'ember';
export default Ember.Controller.extend({
actions: {
createUser() {
console.log("create");
}
}
});
The route:
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.createRecord('admin/create-user');
}
});
The template:
<h3>Create User</h3>
<div class="row">
<div class="col-sm-6">
{{#em-form action="createUser" model=admin/create-user}}
{{em-input
label="Name / Entity"
property="entity"
placeholder="The name of the user or the entity"}}
{{/em-form}}
</div>
</div>
I know I'm missing something and I'm pretty sure it has to do with the model (I tried a lot of thing such as model=admin/create-user in the template).
EDIT: there's no error or whatever in the console, the validation is just not called.
Thx for your help!
The first thing that jumps out at me is the fact that you never, anywhere in your code, check to see if the data is valid via:
// Somewhere in your controller
this.get('isValid');
The second is that you're validations are defined on the controller rather than the model. That works great if your controller extends ObjectController (which is now deprecated) which proxies properties automatically to the model.
If you're extending Controller and you want to validate the model, you need to define them a bit differently:
validations: {
'model.entity': {
presence: true,
length: { minimum: 5 }
}
}
The third is that you're never actually passing an instance of your model to the controller via the route (even though validations should still work):
export default Ember.Route.extend({
model: function() {
// assuming you're using Ember Data
// find the model with id of 1
return this.store.find('admin/create-user', 1);
}
});