ExtJS: Using remotely loaded singleton values for store definition
I'm having some trouble trying to figure out how to do this (if it's even possible).
I have an app which uses parse.com to store it's data, the thing is I want each user to have a different parse.com account so their data sets don't intersect whatsoever. So I created a singleton (Settings) which stores the user's appId and apiKey, which are loaded from a general parse.com account which is managed by me and contains each user's email, appId and apiKey, so when they log into the app it gets the user's appId and apiKey.
The thing is I need to use those settings, appId and apiKey, in the definitions of my stores, as I need to send them in the headers. I've done some testing trying to set my singleton's globals when the app launchs, but at the time of the stores definition both of those "globals" are null, as the app hasn't launched yet.
Here's some of my code so I can make myself a little clearer as I know this isn't the easiest thing to understand.
Application.js
Ext.define('Settings', {
singleton: true,
appId: null,
apiKey: null
});
Ext.define('MyApp.Application', {
extend: 'Ext.app.Application',
name: 'MyApp',
stores: [],
launch: function () {
Ext.create('MyApp.store.Settings').load({
params: {
'where': '{"email": "useremail@gmail.com"}' //email is supposed to be a user input but for the sakes of testing I just made it static
},
callback: function(records){
var s = records[0];
Settings.appId = s.get('appId');
Settings.apiKey = s.get('apiKey');
Parse.initialize(Settings.appId, Settings.apiKey);
}
});
},
onAppUpdate: function () {
Ext.Msg.confirm('Application Update', 'This application has an update, reload?',
function (choice) {
if (choice === 'yes') {
window.location.reload();
}
}
);
}
});
Store
Ext.define('MyApp.store.Things', {
extend: 'Ext.data.Store',
model: 'MyApp.model.Thing',
proxy: {
type: 'rest',
api: {
read: 'https://api.parse.com/1/classes/Thing',
create: 'https://api.parse.com/1/classes/Thing'
},
reader: {
type: 'json',
rootProperty: 'results'
},
useDefaultXhrHeader: false,
withCredentials: false,
headers: {
'X-Parse-Application-Id': Settings.appId, //this is null at the time of definition, but I want it to be the newly fetched value at the time of app launch
'X-Parse-REST-API-Key': Settings.apiKey, //this is obviously null as well
'Content-Type': 'application/json'
}
},
autoLoad: true,
autoSync: true
});
What's the way around this?
By the way.. if someone can think of a proper name for this thread please feel free to change it or suggest.
试试像这样:
Ext.define('Settings', {
singleton: true,
appId: null,
apiKey: null
});
Ext.define('MyApp.store.Things', {
extend: 'Ext.data.Store',
model: 'MyApp.model.Thing',
proxy: {
type: 'rest',
api: {
read: 'https://api.parse.com/1/classes/Thing',
create: 'https://api.parse.com/1/classes/Thing'
},
reader: {
type: 'json',
rootProperty: 'results'
},
useDefaultXhrHeader: false,
withCredentials: false,
},
//autoLoad: true,
autoSync: true
});
Ext.define('MyApp.Application', {
extend: 'Ext.app.Application',
name: 'MyApp',
stores: ['Things'],
launch: function() {
var settings = Ext.create('MyApp.store.Settings');
settings.on('load', function() {
var things = Ext.getStore('Things');
things.getProxy().setHeaders({
'X-Parse-Application-Id': Settings.appId,
'X-Parse-REST-API-Key': Settings.apiKey,
'Content-Type': 'application/json'
});
things.load();
});
settings.load({
params: {
'where': '{"email": "useremail@gmail.com"}' //email is supposed to be a user input but for the sakes of testing I just made it static
},
callback: function(records) {
var s = records[0];
Settings.appId = s.get('appId');
Settings.apiKey = s.get('apiKey');
Parse.initialize(Settings.appId, Settings.apiKey);
}
});
},
onAppUpdate: function() {
Ext.Msg.confirm('Application Update', 'This application has an update, reload?',
function(choice) {
if (choice === 'yes') {
window.location.reload();
}
}
);
}
});
I would suggest using routes to accomplish this, since you are using ExtJs 6. It is completely out of the box, but I thing it would be ideal for your situation. In this way you can simply be sure that when a route is called and a part of your application is loaded, you always can do some checks. This can be very useful for checking user credentials for example. More information about routes can be found here. And this is a great post when you want to handling user sessions through routes.
The singleton:
Ext.define('Settings', {
singleton: true,
appId: null,
apiKey: null
});
The Base store:
Ext.define('Base', {
extend: 'Ext.data.Store',
alias: 'store.base',
storeId: 'base',
autoLoad: false,
proxy: {
type: 'rest',
useDefaultXhrHeader: false,
withCredentials: false
},
listeners: {
beforeload: function(store, operation, eOpts) {
store.getProxy().headers = {
'X-Parse-Application-Id': Settings.appId,
'X-Parse-REST-API-Key': Settings.apiKey,
'Content-Type': 'application/json'
}
}
}
});
The Things store:
Ext.define('MyApp.store.Things', {
extend: 'MyApp.store.Base',
alias: 'store.things',
model: 'MyApp.model.Thing',
storeId: 'things',
requires: [
'Settings'
],
proxy: {
api: {
read: 'https://api.parse.com/1/classes/Thing',
create: 'https://api.parse.com/1/classes/Thing'
},
reader: {
type: 'json',
rootProperty: 'results'
}
},
autoLoad: false, // --> set to false
autoSync: true
});
Your MainController:
Ext.define('MyApp.view.main.MainController', {
extend : 'Ext.app.ViewController',
requires: [
'Settings'
],
stores: [
'Things'
],
routes : {
'user/:id' : {
before : 'onBeforeUser',
action : 'onUser'
}
},
onBeforeUser : function(id, action) {
Ext.create('MyApp.store.Settings').load({
params: {
'where': '{"email": "useremail@gmail.com"}' //email is supposed to be a user input but for the sakes of testing I just made it static
},
callback: function(records){
var s = records[0];
Settings.appId = s.get('appId');
Settings.apiKey = s.get('apiKey');
Parse.initialize(Settings.appId, Settings.apiKey);
action.resume();
}
});
// or even better
Ext.Ajax.request({
url: 'url/to/the/api',
params: {
'where': '{"email": "useremail@gmail.com"}' //email is supposed to be a user input but for the sakes of testing I just made it static
},
success: function(response, opts) {
var obj = Ext.decode(response.responseText);
Settings.appId = obj.appId;
Settings.apiKey = obj.apiKey;
Parse.initialize(Settings.appId, Settings.apiKey);
action.resume();
},
failure: function(response, opts) {
action.stop(true);
}
});
},
onUser : function(id) {
Ext.getStore('things').load();
}
});
I think the issue can be solved by moving proxy definition to constructor of 'Things' store as given below.
Ext.define('MyApp.store.Things', {
extend: 'Ext.data.Store',
model: 'MyApp.model.Thing',
autoLoad: true,
autoSync: true,
constructor: function(config) {
config = Ext.apply({
proxy: {
type: 'rest',
api: {
read: 'https://api.parse.com/1/classes/Thing',
create: 'https://api.parse.com/1/classes/Thing'
},
reader: {
type: 'json',
rootProperty: 'results'
},
useDefaultXhrHeader: false,
withCredentials: false,
headers: {
'X-Parse-Application-Id': Settings.appId,
'X-Parse-REST-API-Key': Settings.appId,
'Content-Type': 'application/json'
}
}
}, config);
this.callParent([config]);
}
});
When proxy definition is inside the constructor, Settings.appId and Settings.apiKey are resolved only at the time of instance creation of 'MyApp.store.Things'.
链接地址: http://www.djcxy.com/p/28600.html