I'm trying to create simple ExtJs application that manages Users and User's Roles. Set of REST services provide this functionality on back end.
When I assign a new Role to a User, appropriate data store sends POST (create) requests to the service. However when I remove existing Role from a User, it's removed only from store locally without sending DELETE request to the service.
Here is my code:
Model:
Ext.define('UserRole', {
extend: 'Ext.data.Model',
fields: [
{ name: 'Id', mapping: "Id" },
{ name: 'RoleId', mapping: "RoleId" },
{ name: 'UserId', mapping: "UserId" }
]
});
Store With proxy:
Ext.define('UserRoleStore', {
extend: 'Ext.data.Store',
model: 'UserRole',
autoload: false,
proxy: {
type: 'ajax',
reader: {
type: 'json',
root: 'd.results'
},
api: {
read: '/accessmanager.svc/Users(\'{userid}\')/Roles?$format=json',
create: '/accessmanager.svc/UserRoles?$format=json',
update: '/accessmanager.svc/UserRoles?$format=json',
destroy: '/accessmanager.svc/UserRoles?$format=json'
},
updateApiUrlWithUserId: function (userId) {
this.api.read = this.api.read.replace('{userid}', userId);
}
}
});
Method that based on selected checkboxes updates the UserRole store
var chekboxes = Ext.ComponentQuery.query('userdetails #roleslist')[0];
var selectedUserId = this.selectedUserId;
var selectedUserRoleStore = this.selectedUserRoleStore;
Ext.each(chekboxes.items.items, function (cb) {
var exists = false;
Ext.each(selectedUserRoleStore.data.items, function (cs) {
if (cs.data.RoleId === cb.inputValue) {
exists = true;
}
});
if (cb.getValue() && !exists) {
var newRole = Ext.create('UserRole', { RoleId: cb.inputValue, UserId: selectedUserId });
selectedUserRoleStore.add(newRole);
} else if (exists && !cb.getValue()) {
// delete existing role
var record = selectedUserRoleStore.findRecord("RoleId", cb.inputValue);
selectedUserRoleStore.remove(record);
}
});
selectedUserRoleStore.sync();
Presumably your Id field is assigned on the server end when record is created. Correct? First try to specify idProperty: 'Id' in the model. Default value for this is 'id' but I think these are case sensitive.
Using idProperty ExtJs recognizes records as being 'dirty' and required to be updated on the server end.
The issue is your proxy needs to be a specialized REST type:
proxy: {
type: 'rest',
http://docs.sencha.com/ext-js/4-0/#!/api/Ext.data.proxy.Rest
Also, you will probably be able to use the buildURL method to replace your own updateAPI... method.
Related
I used to write this in extjs4:
Ext.define('Superstore', {
extends: 'Ext.data.Store'
config : {
customer : null,
},
applyCustomer : function (value) {
this.customer = value;
},
model : 'Supermodel'
});
I tried the same in extjs6, but with no success:´
Ext.define('Supermodel', {
extend: 'Ext.data.Model',
requires: ['Ext.data.reader.Json', 'Ext.data.proxy.Rest'],
config: {
customer: null
},
fields: [
{name: 'id', type: 'string'},
...
],
proxy: {
type: 'rest',
url: '/customers/{customer}/users',
reader: {
type: 'json'
}
},
applyCustomer: function (value) {
this.customer = value;
this.proxy.url.replace('{customer}', value);
}
});
Did they remove the magic?
Or is there any other, better, way to build my url like in my code?
I've already seen a few solutions, but none of them fitted to my application.
I get the customerId via session which is sent by the backend after login. I would get the store via StoreManager, get the customer record and apply it to the proxy.
Thanks in advance.
If you don't need to manipulate the value use the update function instead:
updateCustomer: function(newValue){
this.proxy.url.replace('{customer}', newValue);
}
(And remove the applyCustomer function)
i'm trying to save some app settings to the LocalStorage.
I have a model with the LocalStorageProxy, I have a Store with the model and autoload = true.
I sync the store after adding a record.
The corresponding Docs: http://docs-origin.sencha.com/touch/2.4.0/#!/api/Ext.data.proxy.LocalStorage
But after reloading the app in the browser (Chrome) the data are lost. Addidionally to the autoload flag i do a manual store.load() in the launch method of the application.
All is working fine until i reload the app.
Any ideas on that? Thanks!
the model:
Ext.define('LwvMediaReminder.model.Setting', {
extend: 'Ext.data.Model',
requires: [
'Ext.data.Field',
'Ext.data.proxy.LocalStorage'
],
config: {
idProperty: 'settingsId',
fields: [
{
name: 'settingsId',
type: 'int'
},
{
name: 'bPush',
type: 'boolean'
},
{
name: 'bEmail',
type: 'boolean'
},
{
name: 'sEmail',
type: 'string'
},
{
name: 'sToken',
type: 'string'
}
],
proxy: {
type: 'localstorage',
id: 'settings'
}
}
});
the store
Ext.define('LwvMediaReminder.store.SettingsStore', {
extend: 'Ext.data.Store',
alias: 'store.SettingsStore',
requires: [
'LwvMediaReminder.model.Setting'
],
config: {
autoLoad: true,
model: 'LwvMediaReminder.model.Setting',
storeId: 'SettingsStore'
}
});
the method in my SettingsController that should save the settings object, i always use only one record with the id 0:
onSaveSettingsButtonTap: function(button, e, eOpts) { var mainView = this.getMainView(),
store = Ext.getStore('SettingsStore'),
properties = {
settingsId: 0,
bPush: this.getPushCheckbox().isChecked(),
bEmail: this.getEmailCheckbox().isChecked(),
sEmail: this.getEmailField().getValue(),
sToken: this.getTokenField().getValue()
},
record = store.getById(0),
save = true;
// some form validation
if (properties.bEmail) {
if (properties.sEmail === '') {
save = false;
Ext.Msg.alert('Fehler', 'Bitte geben sie auch eine gültige Email-Adresse an.');
}
if (!this.validateEmail(properties.sEmail)) {
save = false;
Ext.Msg.alert('Fehler', 'Die angegebene Email-Adresse ist nicht gültig.');
}
}
// save the record
if (save) {
if (null !== record) {
record.set(properties);
} else {
store.add(properties);
}
store.sync();
mainView.pop();
}
},
I think i have found the solution.
It seems that the LocalstorageProxy has problems with given object ids.
I was setting the Object Id to 0 by default because i wanted only one object at a time with all my settings in one object.
Unfortunatly the local-storage wasn't able to write it to the browser storage.
No I have rewritten the code so that sencha can set the Id by itself. Now it seems to works fine.
And i can access the record by calling the .first() function from the store.
new code snippet:
var store = Ext.getStore('SettingsStore'),
// no preset id anymore
properties = {
bPush: this.getPushCheckbox().isChecked(),
bEmail: this.getEmailCheckbox().isChecked(),
sEmail: this.getEmailField().getValue(),
sToken: this.getTokenField().getValue()
},
// reading the first entry because there is always only one in my app
record = store.first();
I hope that will help somebody in the future.
I created a model like
Ext.define('MyApp.model.ContainerDetailsModel', {
extend: 'Ext.data.Model',
alias: 'model.ContainerDetailsModel',
config: {
fields: [
{
name: 'id',
allowNull: false,
type: 'string'
},
{
name: 'container_types_id',
type: 'string'
}
]
}
});
and a store like this
Ext.define('MyApp.store.ContainerDetailsStore', {
extend: 'Ext.data.Store',
requires: [
'MyApp.model.ContainerDetailsModel'
],
config: {
model: 'MyApp.model.ContainerDetailsModel',
storeId: 'ContainerDetailsStore',
proxy: {
type: 'ajax',
enablePagingParams: false,
url: 'hereIsServiceUrl',
reader: {
type: 'json'
}
}
}
});
Now somewhere in application I tried to get one record like:
var detailsStore = Ext.getStore("ContainerDetailsStore");
detailsStore.load();
var detailsRecord = detailsStore.last();
But it gaves me undefined. The json returned by service is ok, it use it in different place as source for list. I already tried to change allowNull to true, but there is no null id in source. I tried set types to 'int' with the same result.
So I have tried
console.log(detailsStore);
Result is like this (just important values):
Class {
...
loaded: true,
data: Class {
...
all: Array[1] {
length: 1,
0: Class {
container_types_id: "1",
id: "726",
....
}
...
}
...
},
...
}
In the same place
console.log(detailsStore.data);
returns (as it should):
Class {
...
all: Array[1] {
length: 1,
0: Class {
container_types_id: "1",
id: "726",
....
}
...
}
but (next line)
console.log(detailsStore.data.all);
returns
[]
And it's empty array. When i try any methods from the store it says the store is empty.
I wrote console.log() lines one after another - so for sure it doesn't change between them (I try it also in different order or combinations).
My browser is Google Chrome 23.0.1271.97 m
I use Sencha from https://extjs.cachefly.net/touch/sencha-touch-2.0.1.1/sencha-touch-all-debug.js
How can I take a record from that store?
store.load() Loads data into the Store via the configured proxy. This uses the Proxy to make an asynchronous call to whatever storage backend the Proxy uses, automatically adding the retrieved instances into the Store and calling an optional callback if required. The method, however, returns before the datais fetched. Hence the callback function, to execute logic which manipulates the new data in the store.
Try,
detailsStore.load({
callback: function(records, operation, success) {
var detailsRecord = detailsStore.last();
},
scope: this
});
Im stack with ext js 4 at the very beginning. Im trying to get the current user data when starting the application using store. But Im not getting any data from the store, even the store.count return 0.
I found many description how to create store, but not how to access the data in it. I managed to get the data using Ext ajax request, but i think would be better using store and i cant avoid them..
My model:
Ext.define('MyApp.model.User', {
extend: 'Ext.data.Model',
fields: [
'id',
'username',
'email'
]
});
My store looks like:
Ext.define('MyApp.store.User.CurrentUser', {
extend: 'Ext.data.Store',
requires: 'MyApp.model.User',
model: 'MyApp.model.User',
autoLoad: true,
proxy: {
type: 'ajax',
method: 'POST',
url: Routing.generate('admin_profile'),
reader: {
type: 'json',
root: 'user'
}
}
});
The returned json:
{
"success":true,
"user":[{
"id":1,
"username":"r00t",
"email":"root#root.root"
}]
}
And the application:
Ext.application({
name: 'MyApp',
appFolder: '/bundles/myadmin/js/app',
models: ['MyApp.model.User'],
stores: ['MyApp.store.User.CurrentUser'],
//autoCreateViewport: true,
launch: function() {
var currentUser=Ext.create('MyApp.store.User.CurrentUser',{});
/*
Ext.Ajax.request({
url : Routing.generate('admin_profile'),
method: 'POST',
success: function(resp) {
var options = Ext.decode(resp.responseText).user;
Ext.each(options, function(op) {
var user = Ext.create('MyApp.model.User',{id: op.id,username:op.username,email:op.email});
setUser(user);
}
)}
});
*/
currentUser.load();
alert(currentUser.count());
}
});
The problem itself isn't that the store does not contain data, the problem is that the store load is asyncronous therefore when you count the store records, the store is actualy empty.
To 'fix' this, use the callback method of the store load.
currentUser.load({
scope : this,
callback: function(records, operation, success) {
//here the store has been loaded so you can use what functions you like
currentUser.count();
}
});
All the sencha examples have the proxies in the store, but you should actually put the proxy in the model, so that you can use the model.load method. the store inherits the model's proxy, and it all works as expected.
it looks like model.load hardcodes the id though (instead of using idProperty), and it always has to be an int, as far as I can tell.
good luck!
If got a sencha touch application, with a login form. For returning users, I would like to store the login credentials in the local storage.
User.js
App.models.User = Ext.regModel('User', {
fields: [
{
name: 'username',
type: 'string'
}, {
name: 'password',
type: 'string'
}
],
proxy: {
type: 'localstorage',
id: 'p2s-users'
}
});
Users.js
App.stores.users = new Ext.data.Store({
model: 'User',
autoLoad: true
});
Now I try to sync the form values with local storage, how can I do that, what's the activity flow for reading / getting it?
For reading I would do:
var model = new App.models.User();
users = App.stores.users.load();
if (users.data.length > 0 ) {
model = users.getAt(0);
} else {
App.stores.users.create();
}
form.load(model);
Writing:
form.model.set(form.data);
form.model.save();
App.stores.users.sync();
Somehow it looks too complicate to me (and it doesn't work anyway). How would you solve the problem?
First make sure your saving the models right. For example do this:
var model = new App.models.User();
model.data.username = 'theUser';
model.data.password = 'thePass';
model.save(); //the actual saving. Use chrome developer tools to see the local storage
Then load the model from the localstorage
users = App.stores.users.load();
model = users.getAt(0);
Check if the loaded model is OK and load that to the form with load(model)
The form could be like this:
new Ext.Application({
launch: function() {
new Ext.form.FormPanel({
id:'theForm',
fullscreen: true,
defaults: {
labelAlign: 'top',
labelWidth: 'auto',
},
items: [
{
id : 'userName',
name : 'username',
label: 'Email',
xtype: 'emailfield',
},
{
id : 'userPassword',
name: 'password',
label: 'Password',
xtype: 'passwordfield',
}
]
});
}
});
Then load the record like this Ext.getCmp('theForm').load(users.getAt(0));
To get the model from the form: Ext.getCmp('theForm').getRecord();
From a cursory look, it looks like a possible way to do it.
But, you should create model instances from the model manager, for instance:
Ext.ModelMgr.create({username: 'foo', password: 'bar'}, 'User');