Ive been stuck with this issue for some time
My JSon store fields need to retrieve some more info:
{ name: "ExpirationDate", convert: convertDate },
{ name: "AffectedObject", convert: GetValue },
The date method is working fine but the result from GetValue is not being rendered on the grid even though the code is working and returning the correct value (either with or without JSON):
function GetValue(v) {
var conn = new Ext.data.Connection();
conn.request({
url: 'test/GetObjectByID',
method: 'POST',
params: { id: v },
scriptTag: true,
success: function (response) {
console.log(response.responseText);
ReturnResult(response.responseText);
},
failure: function () {
Ext.Msg.alert('Status', 'Something went wrong');
}
});
function ReturnResult(str) {
return Ext.util.JSON.decode(str.toString());
}
Any idea why the result is not not showing?
The 'convert' property is expecting an immediate return value. Your GetValue function is issuing an asynchronous request and then immediately returning nothing. At some arbitrary point in the future after the request completes the 'success' function is called, but it is no longer connected to the original call so any value it may return is meaningless.
Though you could make it work by replacing the use of Ext.data.Connection with manually constructed synchronous requests, I recommend reconsidering the mechanism by which you are getting this data. Issuing a separate request for every record in your data store is less than optimal.
The best solution is to bring that additional data in on the server side and include it in the response to the store proxy's initial request. If that cannot be done then you can try listening to the store's 'load' event and performing conversion for all loaded records with a single request. Any grids or other views you have reading from the store may have to be configured to display dummy text in place of the missing data until the conversion request completes.
Related
When the user clicks a button, I want the app to
read text from an input field
post it to MySQL to add as a new row
pull all rows from MySQL (including the new row)
update the react component state with the new data it just pulled
and rerender a list of all that data for the user
The problem I'm seeing is that pulling down all rows doesn't include the one that was just posted unless I include a manual delay (via setTimeout).
This is what my 2 functions look like
// gets all data, updates state, thus triggering react to rerender
listWords() {
setTimeout(() => fetch("http://localhost:9000/listWords")
.then(res => res.text())
.then(res => this.setState({ wordList: JSON.parse(res)})), 2000)
}
// sends new word to the MySQL database, then kicks off the listWords process to refetch all data
addWord() {
fetch("http://localhost:9000/addWord", {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
word: this.state.newWord
})
})
.then(res => res.json())
.then(this.listWords())
}
I shouldn't have to have that setTimeout in there, but when I remove it, the listWords update doesn't have the newly posted row.
My best guess is that either
I'm messing up the promise .then() paradigm, or
MySQL responds to my POST request but doesn't actually add the row until the GET has already completed, thereby missing out on the new row.
How can I ensure the POST has successfully completed before I pull the rows again?
I am using react, express, sequelize, and for the DB it's MySQL in a docker container.
You indeed made a mistake, a common trap which I myself fell into as well a few times :)
When calling addWord() it will evaluate then(this.listWords()). This will immediately call listWords().
Instead you pass a function to then(...) (instead of calling a function) for example like this:
.then(() => this.listWords())
or even like this:
.then(this.listWords)
Now, instead of passing the result of listWords() to then() it will pass a function that will call listWords() to then() thus only executing listWords() when the Promise reaches this then()
Example to make this behavior even clearer:
When calling a function function foo(arg1) {}, JS needs to know the value of arg1 before calling foo. Let's take the following piece of code:
foo(bar())
In this case, bar() must be called before foo(...) because the arg1 will be the returned value of bar(). In constrast to the following case:
foo(() => bar())
Now, arg1 will be a function instead of the returned value of bar(). This is equivalent to:
var arg = () => bar();
foo(arg);
In contrast to:
var arg = bar();
foo(arg);
Where it is obvious what will happen.
In chained functions like foo(arg1).bar(arg2).baz(arg3), all args will be evaluated before calling foo(...).
Some help to debug such problems: Use the Network Inspector in your browser. It will show the order of requests performed and in this example you would have seen that the GET request was actually performed before the POST request. This might not explain why it happens but you can understand the problem faster.
i am newbie en react technologie.
how can i get the json data from http request ?
as you can see on
i can get the value of console.log(dataExt); from inside this function,
but i can not get the value of console.log(dataExt); from outside this function.
i miss something ?
i did use return dataExt; why i get nothing ?
i have modified my function:
async function getDataExt()
{
try {
let response = await fetch('https://xxxx');
let dataExt = await response.json();
console.log(dataExt);
return dataExt;
} catch(error) {
console.error(error);
}
}
but still i can not get the value
The fetch call is asynchronous and returns a Promise, that's why you need to call then to get the result. As it stands, line 62 will not wait for the fetch in getDataExt() to complete before running the console.log. You need to treat getDataExt as an async function and either do async/await or .then().
It is because of the asynchrony, that is, the "return" is executed when it obtains the value in the request it makes, and that takes time. Let's say it takes 1 second for the data to return, but 0.1 for the variable to print, that means it prints first and then assigns the value. Now, a possible solution would be to create a "state" to save that data or how the partner said, create the function getDataExt as an asynchronous function.
My backend is Parse.com's REST API, and parse send me back a results object that looks like:
{
...fields...
}
when there is only object, meaning any time there is a create, a read or an update to one record. When I GET a collection of objects from Parse, it sends out a results object that looks like:
{
results: [
{
...fields...
}
]
}
In ST, when I have my proxy's reader's rootProperty set to: 'results', my reader isn't able to read the record Parse sends on a create or an update and therefore the local record doesn't get synced with the one the server sent.
When I have my reader's rootProperty set to: '', my local record gets synced with the one that Parse sent, but now my list, which takes a store, isn't displaying the list of records, because Parse sends that with a "results" node.
I tried using setRootProperty, but despite confirming that the reader's root property just before calling save() on a record is in fact: '', the local record doesn't sync with Parse's response. As soon as I remove the logic that does real time changes to root property, it starts working again.
What is the suggested way of handling this situation? Any help is much appreciated! Thanks!
So you have one store with a proxy that has a certain rootProperty but you olso have 2 type of response, single object or an array of objects inside results. If it is so, definitly your proxy is able to read only one type of response.
Some solutions:
-if you can operate on server make sure you send always an array of results whether the response contains none, one or many results.
-implement a custom reader (this is what i did when i had to manage different responses and make some changes on data in the meanwhile)
Ext.define('MyApp.store.MyStore',{
extend:'Ext.data.Store',
model:'MyApp.model.MyModel',
proxy: {
type:'jsonp',
url:'#'
},
autoLoad:false,
loadSolr:function(PARAMS){
this.groupField = groupField;
Ext.data.JsonP.request({
scope:this,
url: 'http://myserver.com',
callbackKey: 'json.wrf',
params: {
PARAMS
},
success: function(response) {
// handle your response here
var records = [];
Ext.each(response.results, function(record){
records.push({
field1: record.field1,
field2: record.field2
});
});
//load your data into store
this.loadData(records);
}
});
}
});
Hope it helps, post some code if i misunderstood something
I have a very simple app that loads a JSON array using $http.get inside of a controller. It assigns the result data to scope and the HTML repeats through the results to display a list. It is a very simple angularjs example.
function ViewListCtrl($scope, $http) {
$scope.shoppinglist = [];
$scope.loadList = function () {
var httpRequest = $http({
method: 'POST',
url: 'viewList_service.asp',
data: ''
}).success(function (data, status) {
$scope.shoppinglist = data;
});
};
$scope.loadList();
}
While testing on a slow server I realized there was a 3 second blocking delay while rending the repeat region. Debugging revealed to me that my controller does not attempt to get the data until the page is loaded. My page takes 3 seconds to load. Then I must wait another 3 seconds for the json data to load.
I want to load data as soon as possible so it is ready when my controller is ready. Simply put, I want to pre-load the data so it loads in parallel to my module.
I've searched all over and the closest thing I found was "resolve", but I am not using routes. This is a very simple list and no routes or templates.
How can I load the JSON as soon as the page starts to render so it is ready when the controller is ready and there is no blocking... and then get that data into scope?
You can use the module.run method. Which is executed after the config stage is completed. To make use of this you need to create a service factory that does the actual query and caches the result
module("myapp",[]).factory('listService', function($q,$http) {
var listData;
var defer = $q.defer();
return {
loadList: function() {
if(listData) {
defer.resolve(listData);
}
else {
var httpRequest = $http({
method: 'POST',
url: 'viewList_service.asp',
data: ''
})
.success(function(data) {
listData=data;
defer.resolve(listData);
}
}
return defer.promise;
}
}
});
In your controller you still use the factory to get the data with a promise then wrapper.
listService.loadList().then(function(data) {
$scope.shoppinglist=data;
});
This way you can make the async call even before any controller related code executes.
You can load data by writing code (something like Chandermani's listService) in separate file but without using angular. you can use jquery ajax to load your data.
Then write a service in angular to read that data and pass it to your controller.
It sounds like your latency comes from a slow network + server, and not a large amount of data.
So, you could render a tag into your page, so that the data would be sent along with the page HTML response. The downside there is that you're hard-coding your data into your page. This tag would basically pre-seed the $http cache with your data.
var listJson = {...json data here, rendered server-side...};
mod.run(function($cacheFactory) {
var cache = $cacheFactory('yourListCacheId');
cache.put('list-cache-id', listJson);
// store "cache" somewhere you can retrieve it, such as a service or value.
});
Then either use the $http cache property, or wrap $http in a custom service which checks the cache.
Of course, the root of the problem is that your server takes 3 seconds per request, when you normally want that at least in the sub-second range.
I am currently having trouble of reloading a json store with new parameters. Here is my store:
newsletters = new Ext.data.JsonStore({
url: '/newsletters/',
root: 'results',
fields: [
'id',
'body'
'recipients'
],
baseParams: { command: 'json', to: dateTo, from: dateFrom },
autoLoad: true
});
dateTo and dateFrom are initally empty strings ( '' ) and checking in firebug /newsletters is called with the correct parameters.
Now none of the following techniquest work:
Changing the values of dateTo and dateFrom then calling newsletters.reload() still calls the page with the parameters to and from being empty strings.
Calling newsletters.reload( { to: 'test1', from: 'test2' } ); still sees the parameters as empty strings.
Finally as from the manual I have tried:
lastOptions = newsletters.lastOptions;
Ext.apply(lastOptions.params, {
to: 'test1',
from: 'test2'
});
newsletters.reload(lastOptions);
This again does not request /newsletters with the updated parameters.
Any advice appreciated!
You can actually pass params object to the load() method
newsletters.load({
params: {to: 'test1', from: 'test2'}
})
From the docs, you can probably do :
store.setBaseParam('to', dateTo);
Now, if I understand correctly, you want your baseParams to be changed whenever dateTo and dateFrom are changed.
You could try :
var dateTo = '', dateFrom = '';
store.on('beforeload', function(s) {
s.setBaseParam('to', dateTo);
s.setBaseParam('from', dateFrom);
});
// This should work :
dateTo = 1;
dateFrom = 2;
store.load();
My problem was: I have a store that shall request data over a proxy to back-end. This request shall hold a parameter named filter, which will just help back-end to decide which is the set of result the client is interested in. This parameter is loaded from a Combobox or some other component which the user can use to express which filter shall be used.
From my point of view the parameters shouldn't be set to the Store and neither using the load parameter. I will explain why:
Configuring parameters to the store would imply that every other component using the same store will have this parameters configured, meaning you can have concurrence problems.
And on the second case, it is not interesting to have it configurable over load method, because you don't wanna every single time explicit make use of the load method by your self, remember that there are already some components like paging and custom components that triggers this method.
What would be the right way from my point of view:
Every time that a load is triggered, we just attach the additional parameter in a non-intrusive way. Meaning that the trigger will not need to have any change (remember here trigger could be any component that executes store.load()) and the store shall be not aware about this new parameter.
You can see here clearly that this shall be an operation done before request data to proxy, and in my case I implemented as a listener for the beforeload event. When beforeload is executed, I just aggregate the new parameters to the operation parameter of the listener that according documentation is: beforeload( store, operation, eOpts ). The final implementation is something like:
store.on({
beforeload: function (store, operation, opts) {
Ext.apply(operation, {
params: {
filterName: Ext.getCmp('filterCombo').getValue()
}
});
}
});