PDA

View Full Version : Access data recently added into a store via REST/JSON



ffanf
10 Jul 2012, 7:35 AM
Hi,

I'm working on a Sencha Extjs app using MVC / REST with PHP/MYSQL as a backend.

I'm struggling to get records recently pushed to the store, to be more specific, records I get from the store are not up-to-date.

I'm sure it is a very basic issue but I'm missing something somewhere.

This specific function receive a filename as an argument, set this filename as an "ExtraParam" within the store and reload the store (to get proper elements associated with this filename from the database)

Specific portion of the function


loadViewElements: function(selectedpicture) {
console.log('Selected Picture: ' + selectedpicture);
//Set picture time into store
if (selectedpicture != "0") {
Ext.getStore('pictures.ViewPicture').getProxy().setExtraParam('currentdate', selectedpicture);
}


this.getPicturesViewPictureStore().load();


console.log(this.getPicturesViewPictureStore());
console.log(this.getPicturesViewPictureStore().last());

currentPictureValue = this.getPicturesViewPictureStore().last();
var currentPictureTime = currentPictureValue.getData()['picturetime'];
console.log('Selected Picture (Answer from Server): ' + currentPictureTime);



If I look into the logs when the window get displayed:


Selected Picture: 0
GET https://web-server/app.ph...0&sourceid=0&zoomlevel=0&page=1&start=0&limit=25200 OK 646ms
Object { data={...}, groupers={...}, storeId="pictures.ViewPicture", more...}
Object { internalId="20120710171003", raw={...}, data={...}, more...}
Selected Picture (Answer from Server): 20120710171003


There is no selected picture so the system answer with the "latest picture" found on the hard drive.

Then if I request a specific date:


Selected Picture: 20120710142802
GET https://web-server/app.ph...2&sourceid=0&zoomlevel=0&page=1&start=0&limit=25200 OK 378ms
Object { data={...}, groupers={...}, storeId="pictures.ViewPicture", more...}
Object { internalId="20120710171003", raw={...}, data={...}, more...}
Selected Picture (Answer from Server): 20120710171003


As you can see it answer with the same element than previous request.

If I request another date:


Selected Picture: 20120710132402
GET https://web-server/app.ph...2&sourceid=0&zoomlevel=0&page=1&start=0&limit=25200 OK 738ms
Object { data={...}, groupers={...}, storeId="pictures.ViewPicture", more...}
Object { internalId="20120710142802", raw={...}, data={...}, more...}
Selected Picture (Answer from Server): 20120710142802


As you can see it answer with picture from the previous request. Everything is shifted by one request.

At first I thought that maybe the server did not answered properly, but if I look in details within the JSON answer from the "GET" request (for the last request).


id: "20120710132402"
picture: "/viewer/include/timthum...710132402.jpg&s=3&q=100"
picturewidth: 3072
pictureheight: 1656
picturetime: "20120710132402"



I can see that the server answer with the correct "picturetime" but if I get "picturetime" via:


currentPictureValue = this.getPicturesViewPictureStore().last();
var currentPictureTime = currentPictureValue.getData()['picturetime'];

It displays the previous request, not the one answered by the server.

If I use firebug to look into "console.log(this.getPicturesViewPictureStore());" I can see the proper record (there is and should be only one in the store).



$className "Webcampak.store.pictures.ViewPicture"
> data
> data > items
> data > items > 0
> data > items > 0 > data
> data > items > 0 > data > picturetime: 20120710132402

How could I get up-to-date data from the store ?

I'm a bit lost here as I don't understand how "this.getPicturesViewPictureStore().last()" could answer with a record I cannot even find if I look into this.getPicturesViewPictureStore() via firebug.

Thanks,

scottmartin
11 Jul 2012, 1:19 PM
Is your server sending an encoded response back with success: true in the object?

Scott.

ffanf
11 Jul 2012, 1:51 PM
yes it does:



{"success":true,"message":"Loaded data","data":[{"zoomlevel":0,"sourcename".....

This is the weird part, I get an answer form the server, but if I try to access a record within the store it gives me an answer from the previous request.

At startup the server send back the default picture "A" and picture "A" will be displayed
If I click on a date for picture "B", the server will send back picture "B", picture "A" will be displayed
If I click again on a date for picture "C", the server will send back picture "C", picture "B" will be displayed.

The issue is not located on my view but most likely in the controller.

If I look at console.log() output in firebug once I requested picture "C" (inside the controller)
store.load() ==> Send the request to the server, in firebug I can see the proper JSON answer with requested picture
console.log(store) ==> Contains details from picture "C" (only, as there is and should be only one record in this store)
console.log(store.last()) ==> Contains elements from picture "B"

Why can't I get in console.log(store) and console.log(store.last()) the same record ?

scottmartin
11 Jul 2012, 2:27 PM
Please post your model/proxy/store

Scott.

ffanf
11 Jul 2012, 2:52 PM
Model:
http://pastebin.com/mmK79WvG

Store:
http://pastebin.com/cE8JQgE0

Controller is quite large and I still need to clean a few things :)
http://pastebin.com/JeD6QZYx

Edit: Just replaced code with pastebin links to keep layout/presentation.

Thanks a lot

scottmartin
11 Jul 2012, 4:10 PM
See if the following helps:

load app, edit record 2; source field .. any random data and hit enter to save.
It will return simulated response data from update.php

app


Ext.define('MY.model.User', {
extend: 'Ext.data.Model',
idProperty : 'id', // unique field
fields: [
{name: 'id', type: 'int'},
{name: 'sourceid', type: 'int'},
{name: 'sourcename', type: 'string'},
{name: 'zoomlevel', type: 'int'}
],
proxy: {
type: 'rest', // works with 'ajax' as well
// url: 'data.php',
// extraParams: {currentdate: '0', sourceid: '0', zoomlevel:'0'},
api : {
read : 'data.php',
update : 'update.php',
},

reader: {
type: 'json',
root: 'data'
}
}
});

Ext.onReady(function() {

Ext.create('Ext.data.Store', {
storeId: 'simpleStore',
model: 'MY.model.User',

autoLoad: true,
autoSync: true,

listeners: {
update: function(store,record) {
console.log(record.data);
}
}
});

var store = Ext.data.StoreManager.lookup('simpleStore');

var cellEditing = Ext.create('Ext.grid.plugin.CellEditing', {
clicksToEdit: 1
});

Ext.create('Ext.grid.Panel', {
title: 'Grid',
store: store,
columns: [{
header: 'ID',
dataIndex: 'id'
}, {
header: 'Zoom',
dataIndex: 'zoomlevel',
editor: {
xtype: 'numberfield'
}
}, {
header: 'Source',
dataIndex: 'sourcename',
editor: {
xtype: 'textfield'
},
flex: 1
}],
height: 200,
width: 400,

plugins: [ cellEditing ],

renderTo: Ext.getBody()
});

//store.load();
});


data.php


<?php

// display all records

echo '{
"total": 4,
"data": [
{
"id": 1,
"zoomlevel": 10,
"sourcename": "source name 1"
},
{
"id": 2,
"zoomlevel": 20,
"sourcename": "source name 2"
},
{
"id": 3,
"zoomlevel": 30,
"sourcename": "source name 3"
},
{
"id": 4,
"zoomlevel": 40,
"sourcename": "source name 4"
}
]
}';

?>


update.php


<?php

echo '{
"success": true,
"message": "Loaded Data",
"data": [
{
"id": 2,
"zoomlevel": 200,
"sourcename": "source name 200"
}
]
}';

?>


Regards,
Scott.

ffanf
11 Jul 2012, 5:51 PM
Thanks scott,

I have another portion of the software which read/update/delete records from/to a grid. And this portion works like a charm.

The issue I have here is related to updating/accessing the store directly from the controller, without elements being displayed by the view.

I would like to understand the logic here, and best ways to access/updated a store from a controller.

If you take the controller (http://pastebin.com/JeD6QZYx).

If I click on a grid cell, the event will be caught by onPictureHourSelected (line 104), this function will get the value of the cell and send it to another function using this.loadViewElements(selectedpicture).

Then within loadViewElements function (line 150).
If I click on an cell, I will get the following in Firebug (line 154 not commented):

Selected Picture: 20120708074602
Then right after I see a get request in Firebug, initiated by this.getPicturesViewPictureStore().load(); (line 161).

If I expand the result, and look into "Response":

{"success":true,"message":"Loaded data","data":[{"zoomlevel":0,"sourcename":"Buhl: Grand Ballon - 1424m","id":"20120708074602","sourceid":3,"picture":"\/interface-new2\/remote\/lib\/timthumb.php?src=pictures\/20120708\/20120708074602.jpg&s=3&q=100","picturewidth":3072,"pictureheight":1656,"picturetime":"20120708074602","thumb1":"\/interface-new2\/remote\/lib\/timthumb.php?src=pictures\/20120708\/20120708071602.jpg&s=3&q=100","thumb1time":"20120708071602","thumb2":"\/interface-new2\/remote\/lib\/timthumb.php?src=pictures\/20120708\/20120708072601.jpg&s=3&q=100","thumb2time":"20120708072601","thumb3":"\/interface-new2\/remote\/lib\/timthumb.php?src=pictures\/20120708\/20120708073602.jpg&s=3&q=100","thumb3time":"20120708073602","pictureprevious":"20120708074401","picturenext":"20120708074801","thumb4":"\/interface-new2\/remote\/lib\/timthumb.php?src=pictures\/20120708\/20120708075602.jpg&s=3&q=100","thumb4time":"20120708075602","thumb5":"\/interface-new2\/remote\/lib\/timthumb.php?src=pictures\/20120708\/20120708080602.jpg&s=3&q=100","thumb5time":"20120708080602","thumb6":"\/interface-new2\/remote\/lib\/timthumb.php?src=pictures\/20120708\/20120708081602.jpg&s=3&q=100","thumb6time":"20120708081602","disableddates":"'03\/03\/2012', '03\/04\/2012', '03\/05\/2012', '03\/06\/2012', '03\/07\/2012', '03\/08\/2012', '03\/09\/2012', '03\/10\/2012', '03\/12\/2012', '03\/13\/2012', '03\/14\/2012', '03\/15\/2012', '03\/16\/2012', '05\/26\/2012'","mindate":1330560061000}]}

You can see "id" or "picturetime" ==> 20120708074602 which is the selected date, so the server answer with elements regarding the proper picture.

But then let's say I want to display 'picturetime' (line 169) via console.log, it gives me:

Selected Picture (Answer from Server): 20120712004802

Which is the picture from a previous request. But then if I click on another cell



Selected Picture: 20120708172402
.... GET request, answering with elements from picture 20120708172402
Selected Picture (Answer from Server): 20120708074602


So data manage at some point to be inserted within the store, but I would really love to be able to access those data right after store.load() is called and answer is received from Server.

At some point I thought that maybe the server was taking too long to answer, but if i display the store with console.log(store) I can see the data.

Thanks

ffanf
11 Jul 2012, 6:46 PM
I just found something that might help.

If I start with Chrome, for the first time the function is executed:
this.getPicturesViewPictureStore().load(); ==> Send request to server
console.log(this.getPicturesViewPictureStore()); ==> Display the store, I can see the the proper picture being sent back (latest picture of the directory has no date has been specified).

But then when it comes to calling:
this.getPicturesViewPictureStore().last().getData()['picturetime'] ==> I get an error:
Uncaught TypeError: Cannot call method 'getData' of undefined


So maybe the store is not properly initiated/created within the controller.

Within Chrome, and console.log(this.getPicturesViewPictureStore()) I can see data within "h > proxy > reader > rawData > data > 0 > ..." or "h > data > items > 0 > raw ..." and a few other places.

This error does not appear afterwards, just at the first time the function is processed.

ffanf
13 Jul 2012, 5:54 AM
Hi,

So I finally found the answer, and it's obvious I'm a newbie :)

For some reason this morning latency to my dev server was higher (between 1 and 2s) than usual and I noticed that GET request were still being processed when the object was actually being displayed by console.log.

So the answer was very simple, I was not waiting until the store was loaded before moving forward with processing.
The reason for store records to be shifted by one record was simply that there was sufficient time between two store request for one store to be loaded.

In terms of code, I replaced this:


this.getPicturesHoursListStore().load()


with:


this.getPicturesViewPictureStore().on('load',this.loadViewElements,this,{single:true});this.getPicturesViewPictureStore().load();

This way loadViewElements is fired when store.load() function is completed.

Thanks to this forum post: http://www.sencha.com/forum/showthread.php?185934-How-to-Load-a-Panel-with-data-from-a-Store

Then within my loadViewElements I can access the latest record properly.


loadViewElements: function() { //Load (or reload) all pictures elements based upon selected picture (format: YYYYMMDDHHMMSS), if selectedpicture = "0", picture is taken from current store record console.log('Log: Controller->Pictures->Pictures: loadViewElements: function()'); if (this.getPicturesViewPictureStore().getCount() > 0) { console.log('Log: Controller->Pictures->Pictures: loadViewElements - Store updated'); currentPictureValue = this.getPicturesViewPictureStore().last(); var currentPictureTime = currentPictureValue.getData()['picturetime'] + ""; console.log('Log: Controller->Pictures->Pictures: loadViewElements - Will display elements about: ' + currentPictureTime);
.....

Thanks for your help

scottmartin
13 Jul 2012, 7:08 AM
Ah yes ... you need a listener to 'listen' for the return ;) It is the simple things sometimes!

Scott.