I have a API that sends out a paginated result of data and I want it to be consumed my Ext JS app but I don't know how to supply the needed parameters.
Here is the response I expect:
{
"currentPage": 1,
"from": 1,
"items": [
{
"id": 1,
"customer": "Customer 1",
"movie": "Movie 1",
"dateRented": "2021-01-25T01:22:42.143",
"dateReturned": "2021-01-25T01:22:50.447"
},
{
"id": 2,
"customer": "Customer 2",
"movie": "Movie 2",
"dateRented": "2021-01-25T01:22:42.15",
"dateReturned": "2021-01-25T01:22:54.573"
}
],
"pageSize": 2,
"to": 2,
"totalCount": 1000003,
"totalPages": 500002,
"hasPreviousPage": false,
"hasNextPage": true
}
Here is the endpoint:
/api/Rentals/{currentPage}/{pageSize}
Here is my Ext store but I don't know how I will be able to pass the value for currentPage and pageSize:
Ext.define('Vidly.store.PagedRentals', {
extend: 'Ext.data.Store',
alias: 'store.pagedrentals',
storeId: 'pagedrentals',
model: 'Vidly.model.PagedRental',
autoLoad: true,
autoSync: true,
proxy: {
type: 'rest',
url: 'https://localhost:44313/api/Rentals/',
useDefaultXhrHeader: false,
reader: {
type: 'json',
headers: { 'Accept': 'application/json' },
},
writer: {
type: 'json',
writeAllFields: true
}
},
});
And here is the model:
Ext.define('Vidly.model.PagedRental', {
extend: 'Ext.data.Model',
fields: [
{ name: 'currentPage', type: 'int' },
{ name: 'from', type: 'int' },
{ name: 'to', type: 'int' },
{ name: 'pageSize', type: 'int' },
{ name: 'totalCount', type: 'int' },
{ name: 'totalPages', type: 'int' },
],
hasMany: 'Rental',
});
I hope someone can help me with my problem. Thank you.
Ext's rest proxy is designed to use standard REST APIs where paging and filtering options are passed in as query parameters. I.e. something like
https://localhost:44313/api/Rentals?start=1&limit=25
I would recommend to use this approach rather than a non standard REST API. It will enable you to use Ext's related features seamlessly.
If there is no way to change the API and you need to stick with your current server configuration then you need to create a custom proxy overriding some of the related functions. The best bet if you override the buildUrl function and pass your custom generated URL to the request object.
UPDATE
You can start with this code (also created a Fiddle):
Ext.define('Yournamespace.proxy.custom', {
extend: 'Ext.data.proxy.Rest',
alias: 'proxy.custom',
buildUrl: function(request) {
const url = this.callParent([request]);
const operation = request.getOperation();
console.log(url, this.getParams(operation))
return url;
}
});
Ext.define('User', {
extend: 'Ext.data.Model',
});
Ext.application({
name : 'Fiddle',
launch : function() {
var myStore = Ext.create('Ext.data.Store', {
model: 'User',
pageSize: 10,
proxy: {
type: 'custom',
url: 'https://localhost:44313/api/Rentals/',
reader: {
type: 'json',
rootProperty: 'users'
}
},
autoLoad: true
});
}
});
You can write your custom code to the buildUrl function. Currently only the default URL and the params are collected and logged there but it does the default stuff. You can tweak the URL here and return the new URL at the end.
Related
When I invoke a function from controller that loads data in the store in the following manner,
var store= new Ext.getStore('MyStore');
store.load();
The response header shows that the following JSON data is returned,
{"usrdata":[{"name":"John",
"roll":"5",
"address":"abcd"
}]
}
but the problem is when I write
console.log(store.getTotalCount());
it shows '0' (zero) on the console.
Can somebody please help me identify why is it not showing the actual count of the number of records in the store.
I feel it might be because store has not finished loading when the function is invoked (may be I am not correct).
following is the code of my store:
Ext.define('MyApp.store.MyStore', {
extend: 'Ext.data.Store',
model: 'MyApp.model.MyModel',
timeout : 60000,
proxy: {
type: 'ajax',
api: {
create: 'php/insert.php',
read: 'php/read.php',
update: 'php/update.php',
destroy: 'php/delete.php',
},
reader: {
type: 'json',
root: 'usrdata',
successProperty: 'success'
},
writer: {
type: 'json',
writeAllFields: true,
encode: true,
root: 'usrdata'
}
},
autoLoad: true,
});
Use the callback in the load method to get the record count: http://docs.sencha.com/extjs/4.2.2/#!/api/Ext.data.Store-method-load
store.load({
scope: this,
callback: function(records, operation, success) {
// the operation object
// contains all of the details of the load operation
console.log(records.length);
// Alternative
console.log(store.getTotalCount());
}
});
You need a tiny change in your store definition
Ext.define('MyApp.store.MyStore', {
extend: 'Ext.data.Store',
model: 'MyApp.model.MyModel',
timeout : 60000,
proxy: {
type: 'ajax',
api: {
create: 'php/insert.php',
read: 'php/read.php',
update: 'php/update.php',
destroy: 'php/delete.php',
},
reader: {
type: 'json',
root: 'usrdata',
totalProperty : '<the_node_of_json_response_which_holds_the_count>'
successProperty: 'success'
},
writer: {
type: 'json',
writeAllFields: true,
encode: true,
root: 'usrdata'
}
},
autoLoad: true,
});
PS - your service needs to return the count. getTotalCount() does not return how many records your store contains, it returns the number that the totalProperty of reader object holds.
So if your service is returning the data -
{
"total": 122,
"offset": 0,
"users": [
{
"id": "ed-spencer-1",
"value": 1,
"user": {
"id": 1,
"name": "Ed Spencer",
"email": "ed#sencha.com"
}
}
]
}
your reader object would look like -
reader: {
type: 'json',
root: 'usrdata',
totalProperty : 'total'
successProperty: 'success'
},
Just in case we are solving the wrong problem. Usually you would want a total counter to be always returned from the server along your data, this way pagination etc will all work automatically. See here for examples:
{
"total": 122,
"offset": 0,
"users": [
{
"id": "ed-spencer-1",
"value": 1,
"user": {
"id": 1,
"name": "Ed Spencer",
"email": "ed#sencha.com"
}
}
]
}
I have a model like this:
Ext.define('Policy', {
extend: 'Ext.data.Model',
fields: [
{
name: 'id',
type: 'sting',
phantom: true,
convert: function(value, record) {
return record.get('a') + '#' +
record.get('b');
}
},
{name: 'a', type: 'string'},
{name: 'b', type: 'string'}]
});
Where the PK of each record is a and b. The store looks like this:
Ext.define('Store', {
extend: 'Ext.data.Store',
model: 'Policy',
autoLoad: true,
proxy: {
type: 'rest',
simpleSortMode: true,
batchActions: true,
reader: {
type: 'json',
root: 'data',
idProperty: 'id'
},
writer: {
nameProperty: 'mapping'
},
api: {
create:'/batch',
read: '/policies',
update: '/batch',
destroy: '/batch'
}
}
});
How can I configure the store so that when it POSTS to /batch when calling store.sync(), the payload looks like this and only consists of dirty records:
{
"policies": [{
"a": "AA",
"b": "BB",
}, {
"a": "AAA",
"b": "BBB"
},...]
}
where there is a policies property and under it is an array of dirty policies.
You can create whatever structure you want by making a manual Ext.Ajax() call. You have to submit only the dirty records yourself.
I want to load store data dynamically and don't want to use model for this. if I provide data list gets populated but if I use store's proxy it doesn't get called and url is not getting hit. Please help.
Ext.define('TrainEnquiry.view.SearchTrainResults', {
extend: 'Ext.List',
xtype: 'searchedtrainresult',
requires: 'Ext.data.proxy.JsonP',
config: {
itemId: 'searchedtrainresult',
title: 'Train Result:',
itemTpl: '<div class="myContent">'+
'<div><b>{number}</b> </div>' +
'</div>',
store: {
fields: ['number'],
/*data: [
{number: 'Cowper'},
{number: 'Everett'},
{number: 'University'},
{number: 'Forest'}
]*/
proxy: {
url: 'http://abc.amazonaws.com/search.json',
type:'jsonp',
extraParams : {
'q' : '12313'
},
reader: {
type: 'json',
},
success: function() {
debugger;
console.log('success');
},
failure: function() {
debugger;
console.log('failure');
}
}
},
onItemDisclosure: true
}
});
I think your "fields" config option needs to be a proper Ext.data.Field object, so maybe this would work:
Ext.define('TrainEnquiry.view.SearchTrainResults', {
...
config: {
...
store: {
fields: [ { name: 'number', type: 'string'} ],
proxy: {
...
}
},
...
}
});
(Reference from Sencha forums)
You could try removing the pageParam and startParam from your proxy. Just like this
Ext.create('Ext.data.Store', {
storeId:'UserStore',
autoLoad: true,
model: 'UserModel',
proxy: {
type: 'jsonp', // Because it's a cross-domain
url : 'https://api.twitter.com/1/lists/members.json?owner_screen_name=Sencha&slug=sencha-team&skip_status=true',
reader: {
type: 'json',
root: 'users' // The returned JSON will have array
// of users under a "users" property
},
// Removing pageParam and startParam
pageParam: undefined,
startParam: undefined
}
});
Here is an example http://jsfiddle.net/alexrom7/YNTuN/
Try changing the type of your proxy store to Ajax (type: 'ajax'). Just like this
Ext.create('Ext.data.Store', {
model: 'User',
proxy: {
type: 'ajax',
url: '/test.json',
reader: {
type: 'json',
}
},
autoLoad: true
});
I have model Schedule which associated with another model Chamber.
And i'm getting the problem when associated model data is null.
It's normal behavior, cause it's not required field.
Upgrade: Schedule model is a part of scheduleTree model, which used by store loading data from server.
Ext.define('...SchedulesTree', {
extend : '...TreeStore',
model: "...ScheduleTree",
root: {
expanded: true,
text: "root",
children: [],
loaded: true
},
paramsAsHash : true,
proxy : {
type: "direct",
autoLoad: false,
api : {
read: registratorAction.getScheduleNode
},
reader: {
type: "json",
root : "records",
totalProperty: 'total'
}
}
});
Ext.define("...ScheduleTree", {
extend: "Ext.data.Model",
...
associations: [
{
type: "hasMany",
model: "Unimed.model.staff.Schedule",
name: "schedules",
getterName: "schedules"
}
]
});
Ext.define("...Schedule", {
extend: "Ext.data.Model",
fields: [
{name: "timeBegin", type: "date", dateFormat: "time"},
{name: "timeEnd", type: "date", dateFormat: "time"}
],
proxy: {
type: "direct",
reader: {
type: "json"
}
},
associations: [
{
type: "belongsTo",
model: "..LpuPosition",
associationKey: "lpuPosition",
getterName: "lpuPosition",
associatedName: "lpuPosition"
},
{
type: "belongsTo",
model: "...Chamber",
associationKey: "chamber",
getterName: "chamber",
associatedName: "chamber"
}
]
});
When i'm getting chamber:
chamber = schedule.chamber();
and there is no linked data i'm getting exception: 'Uncaught TypeError: undefined is not a function'.
I can make workaround by looking raw data, but may be there exists more elegance solution?
I want to dynamically set up the left-side navigation menu just like iPad-style.
So, I make some modification on the demo example. You could also visit this official example here.
sink.StructureStore = new Ext.data.TreeStore({
model: 'Demo',
//root: {
// items: sink.Structure
//},
proxy: {
type: 'ajax',
url: 'words.json',
reader: {
type: 'json',
root: 'items'
}
}
});
For easier implementation, I try to get the JSON data from the "words.json".
(Ideally, JSONP type is better...tried, but no luck.)
Here is the content of "words.json":
{
text: 'User Interface',
cls: 'launchscreen',
items: [{
text: 'Buttons',
card: demos.Buttons,
source: 'src/demos/buttons.js',
leaf: true
},
{
text: 'Forms',
card: demos.Forms,
source: 'src/demos/forms.js',
leaf: true
},
{
text: 'List',
card: demos.List,
source: 'src/demos/list.js',
leaf: true
}]
}
It ends up nothing appearing. What's wrong? Do I mistake it? (API here)
What do I want to do?
Like a dictionary, left side are those navigation items of word. On clicking it, the meaning of the word will be showed in right-side view.
I can't run NestedList example in sencha framework. Clicking on the table cell and push another view on it (i.e., in Sencha: NestedList) is what I want to do.
Have tried and no luck:
use the NestedList example
replace proxy with ScriptTagProxy (JSONP)
use easier proxy implementation (showed in the code)
I am not so sure whether my description is clear enough or not, feel free to tell me which part is unclear. And thanks in advance!
If words.json looks like what you have above then that could be your problem.
This is what it should look like.
{
"text": "User Interface",
"cls": "launchscreen",
"items": [{
"text": "Buttons",
"source": "src/demos/buttons.js",
"leaf": true
}, {
"text": "Forms",
"source": "src/demos/forms.js",
"leaf": true
}, {
"text": "List",
"source": "src/demos/list.js",
"leaf": true
}]
}
I've also attached a fully working copy of what you wanted using both a memory proxy (default) and an ajax proxy.
Ext.regApplication({
name: 'test',
launch : function(){
var nL = new Ext.NestedList({
store: test.stores.testTreeStore,
fullscreen: true,
itemTextTpl : '{text}'
});
}
});
Ext.ns('test.data');
test.data.words = {
text: 'User Interface',
cls: 'launchscreen',
items: [{
text: 'Buttons',
source: 'src/demos/buttons.js',
leaf: true
},
{
text: 'Forms',
source: 'src/demos/forms.js',
leaf: true
},
{
text: 'List',
source: 'src/demos/list.js',
leaf: true
}]
};
test.models.testTreeModel = Ext.regModel('testTreeModel', {
fields: ['text','source','card','leaf'],
proxy: {
type: 'memory',
data: test.data.words,
//type: 'ajax',
//url: 'words.json',
reader: {
type: 'json',
root: 'items'
}
}
});
test.stores.testTreeStore = new Ext.data.TreeStore({
model: 'testTreeModel'
});