ExtJS5: Get rid of root property in proxy - rest

I'm trying to connect a REST API to my ExtJS application.
For GET /user alike requests I return a response as follows:
{items: [{id: 1, ...}, {id: 2, ....}], total: 2}
So I created a model for that:
Ext.define('model.User', {
extend: 'Ext.data.Model',
fields: [
{ name: 'id', type: 'int' },
{ name: 'name' },
],
proxy: {
reader: {
type: 'json',
totalProperty: 'total',
rootProperty: 'items'
},
type: 'rest',
url: '/Api/User',
}
});
The grids load data and all look perfect. Now I want to be able to request a single record which my api serves as {id: 1, ...}.
But when I do model.User.load(1) the success handler is never triggered because the response doesn't contain items property. If I put my record in that property, it will work but also will look ugly for other API users.
How can I make it work without the root property? I can't find any events for proxy/reader on a model to change it dynamically.

The rootProperty can also be a function, so you could do something like:
rootProperty: function(raw) {
return raw.items ? raw.items : raw;
}

Related

Comparing JSON array with Mongo array document

Currently I have a mongoose model 'Event' that stores a list of UUIDs as participants that reference another model 'User'
.
participants: [{
_id: false,
id: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
tickets: {
type: Number,
min: 0,
},
}],
winners: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}],
.
.
Now I receive a request with the following JSON data to update my winners
{
"winners": [
"5f61132da98bac2a98487d79",
"5f611378a98bac2a98487d7a",
"5f611378a98bac2a98487d77"
]}
Is there a way to compare this array with participant field of that model and only allow entry of user ids that are participants? For example
const event = await Event.findOne({_id: _id}, 'participants.id -_id');
console.log(event.participants);
Output:
[
{ id: 5f61132da98bac2a98487d79 },
{ id: 5f611378a98bac2a98487d7a },
{ id: 5f6113b1a98bac2a98487d7b }
]
console.log(req.body.rewards);
[
'5f61132da98bac2a98487d79',
'5f611378a98bac2a98487d7a',
'5f611378a98bac2a98487d77'
]
Clearly the last UUID is not matching (is not a participant) so should be discarded and other two remaining should be updated in winners field. JSON object can be made flexible if needed.
Using aggregation framework does not really help me on this problem, and it might be very costly to project specific elements for a single document only. A work around solution would be using arrays.
const event = await Event.findOne({
_id: _eventId,
rewards: { $elemMatch: { _id: _rewardId }}
}, 'participants.id -_id');
const allParticipants = []
(event.participants).forEach((item) => {
allParticipants.push(item.id.toString());
});
const validIds = (req.body.winners).filter(item => allParticipants.includes(item));
This will check for arrays using includes and filter and return matching array item from the request and participants in the event.

js-data mongodb adapter only returning _id from findAll()

I'm using js-data with the mongodb adapter js-data-mongodb. I'm running into an issue where store.findAll is only returning the _id of the record. No other fields are returned.
Here is my record in my artworks collection in mongoDB:
_id: ObjectId("59bb7ee069d99027f5219667")
uid :"599b73c285b13252e7f54161"
title: "t1"
description: "t1"
imageUrl: "this.artwork.imageUrl"
videoUrl: "this.artwork.videoUrl"
Part of my js-data store definition:
// Create a store to hold your Mappers
const store = new Container({});
// Mappers in "store" will use the MongoDB adapter by default
store.registerAdapter('mongodb', adapter, { 'default': true });
store.defineMapper('artwork', {
collection: 'artworks',
schema: artworkSchema,
idAttribute: '_id'
});
And the code in my app:
store.findAll('artwork', {uid: '599b73c285b13252e7f54161'}).then((records) => {
console.log(records);
})
The output:
[ Record { _id: '59bb7ee069d99027f5219667' } ]
What am I missing in order to get all the fields of the record returned in the response?
Thanks!
Update:
Turns out if I remove my schema definition from the mapper, the fields are returned correctly. This is my schema definition. I'm not sure where I'm going wrong here.
const artworkSchema = new Schema({
$schema: 'http://json-schema.org/draft-06/schema#',
title: 'Artwork',
description: 'Schema for Artwork records',
type: 'object',
properties: {
uid: { type: 'string' },
title: { type: 'string' },
description: { type: 'string' },
imageUrl: { type: 'string' },
videoUrl: { type: 'string' }
},
required: ['uid', 'title', 'imageUrl', 'videoUrl']
});
Argh, that was silly of me. The findAll() call was returning an array of Records, with its attributes. The console.log() wasn't showing it but I am able to get the data by using the array index (records[0].title) or using get('title') as described in the documentation.

Error while setting up Extjs Rest Proxy Create function

I am using Rest proxy in Extjs Model as:
Ext.define('ThemeApp.model.peopleModel', {
extend: 'Ext.data.Model', fields: [
{ name: 'userId' },
{ name: 'title' },
{ name: 'body'}
],
proxy: {
type: 'rest',
format: 'json',
limitParam:"",
filterParam: "",
startParam:'',
pageParam:'',
url:'http://jsonplaceholder.typicode.com/posts/1',
api: {
read : 'http://jsonplaceholder.typicode.com/posts/1',
create: 'http://httpbin.org/post'},
headers: {'Content-Type': "application/json" },
reader: {
type: 'json',
//rootProperty:'issues'
},
writer: {
type: 'json'
}
In my view I am calling create function as:
var user = Ext.create('posts', {"userId": 124,"title": "sunt","body": "quia"});
user.save();
As I am testing everything on http://jsonplaceholder.typicode.com/ so I am expecting that code will work cause when I test GET and POST functionality via Postman utility everything works fine.
Can anyone point out my error?
I found my mistake.
In the following code I was not setting the correct name of my model, as it won't be "Posts"
var user = Ext.create('posts', {"userId": 124,"title": "sunt","body": "quia"});
user.save();
Also if you are trying with http://jsonplaceholder.typicode.com/ you are not supposed to send ID in the post request.

Extjs 4.2 Proxy Rest id parameter

I am trying to access a REST service using extjs proxy rest, but the url that is being sent looks weird, take a look:
/rest/v1/distribution-list/1*?id=1*
I dont know why 'id' is being sent.
It shoul send '/rest/v1/distribution-list/1'
Any ideas?
this is my model
Ext.define('Wave.model.DistributionList', {
extend: 'Ext.data.Model',
fields: [
{name: 'id'},
{name: 'name', type: 'string'},
{name: 'status', type: 'string'}
],
proxy: {
type: 'rest',
noCache: false,
reader: {
type: 'json'
},
writer: {
type: 'json'
},
actionMethods: {
create: 'POST',
read: 'GET', // defaults to GET
update: 'POST',
destroy: 'DELETE'
},
api: {
read: '/rest/v1/distribution-list/',
create: '/rest/v1/distribution-list/',
update: '/rest/v1/distribution-list/',
destroy: '/rest/v1/distribution-list/'
}
}
});
Cheers
-Henrique
the ID have been send is setted by Extjs.you can change that using the idParam to changed to other one;
Working with sencha-touch 2.3.1 and rest proxy, ExtJS creates the URL to the action methods with query string parameters, like you said: /rest/v1/distribution-list/?id=1.
If you don't want to append the id, you can change appendId to false inside proxy config.

Form field to pick from a list of objects in a store

I'm new to Sencha, trying to implement a Sencha formpanel with a field to pick from a list of objects in a store. This seems like a sufficiently basic pattern that there must be a simple solution. I have a model which defines an ajax endpoint returning a json array (places) of name/id pairs:
Ext.define('MyApp.model.Place', {
extend: 'Ext.data.Model',
config: {
fields: [
{name: 'name', type: 'string'},
{name: 'id', type: 'int'},
],
proxy: {
type: 'ajax',
url: '/m/places/',
reader: {
type: 'json',
rootProperty: 'places',
},
},
},
});
And a store:
Ext.define('MyApp.store.Place', {
extend: 'Ext.data.Store',
requires: ['MyApp.model.Place'],
config: {
model: 'MyApp.model.Place',
autoLoad: true,
sorters: [
{
property : 'name',
direction: 'ASC',
},
],
},
});
I want a read-only text field for the place name and a hidden field to submit the place id:
{
xtype: 'textfield',
name: 'place_name',
label: 'Place',
readOnly: true,
listeners: {
focus: function () {
var place_picker = Ext.create('Ext.Picker', {
slots: [
{
name: 'place_name',
title: 'Choose a Place',
store: Ext.create('MyApp.store.Place'),
itemTpl: '{name}',
listeners: {
itemtap: function (obj, index, target, record, e, eOpts) {
var form = Ext.getCmp('entityform');
form.setValues({
place_name: record.get('name'),
place_id: record.get('id'),
});
// how to dismiss the picker?
obj.parent.hide();
},
},
},
]
});
Ext.Viewport.add(place_picker);
place_picker.show();
},
},
},
{
xtype: 'hiddenfield',
name: 'place_id',
},
At this point, tapping the field causes the picker to slide up from the bottom and display the loading animation, but it is not being populated with the list of place names, although I can see that the ajax request has been made and that it has returned the expected json document.
I'll stop here and ask if I'm on the right track or is there some better approach out there?
Why isn't the picker being populated with the results of the ajax request? Is my use of itemTpl incorrect?
Am I setting the form fields in a sencha-appropriate way?
How should I dismiss the picker on itemtap? I somehow doubt that my use of hide() is the proper way.
Picker slots has an data config which is an array of objects. It should have a specific format with text and value.
slots :[
data : [{
text : someValue,
value : someValue1,}] ]
You need to add objects which has the fields text and value to slots.