Extjs 5 how to store user detail after login, and use it for data binding in a ViewModel - extjs

I am new to extjs 5. Been spending alot of time trying to learn it, and have a hard time understanding some things.
I have been able to create an authentication system, but the problem im having is where to store the user object. After reading some docs and other answers here on SO, these where the strategies i came up with
Authenticate user and retrieve user data, then :-
Create a Model Instance with user data and store it in a global variable :
Problem is how do i add this to a viewmodel so that i can data bind its fields to a view. For example
bind User Name to text of a button.
Create a model link in the viewModel:
The problem with this is, How do i pass in the model Id so that i can retrieve the user from the server.
Store the user data in a global variable, then in view controller , access viewModel memory store proxy, then add the data to the store, then load the store.
Problem is when i do it this way I still cant access the data in my view for data binding.
Please see snipets below :-
Scenario 1
Application.js
Ext.define('Wilma.Application', {
extend: 'Ext.app.Application',
requires: [
"Wilma.DirectAPI",
'Wilma.view.login.Login'
],
name: 'Wilma',
views: [
'Wilma.view.MyViewport'
],
stores: [
// TODO: add stores here
],
enableQuickTips: true,
launch: function() {
ExtRemote.HWLogin.loginStatus('', function(result, event){
if(result.success){
console.log('i was called' + result.data);
//Global variable
Wilma.app.LoggedInUser = Ext.create(Wilma.model.User, result.data.user);
console.log(Wilma.app.LoggedInUser);
Ext.widget('mainviewport');
}
else {
Ext.widget('login');
}
}
});
});
ViewModel
Ext.define('Wilma.view.header.usermenu.UsermenuModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.usermenu',
requires: [
'Wilma.store.Users',
'Wilma.model.User'
],
// ???????????????
// ???????????????
// What do i do here
});
Scenario 2
App.js
Relevant part:
launch: function() {
ExtRemote.HWLogin.loginStatus('', function(result, event){
if(result.success){
console.log('i was called' + result.data);
//Global variable
Wilma.app.LoggedInUser = Ext.create(Wilma.model.User, result.data.user);
//OR
//Wilma.app.LoggedInUser = result.data.user
console.log(Wilma.app.LoggedInUser);
Ext.widget('mainviewport');
}
else {
Ext.widget('login');
}
}
});
ViewModel
links: {
loggedinuser:{
reference: 'user',
id: Wilma.app.LoggedInUser.get('_id')
}
}
Scenario 3
ViewController
Ext.define('Wilma.view.header.usermenu.UsermenuController', {
extend: 'Wilma.controller.BaseViewController',
alias: 'controller.usermenu',
onbeforerender: function(button, eOpts) {
var userstore = this.getViewModel().getStore('usermenu');
userstore.getProxy().data = Wilma.app.LoggedInUser;
userstore.load();
//userstore.add(Wilma.app.LoggedInUser);
}
});
ViewModel
Ext.define('Wilma.view.header.usermenu.UsermenuModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.usermenu',
requires: [
'Wilma.store.Users',
'Wilma.model.User'
],
stores: {
usermenu: {
model: 'Wilma.model.User',
proxy:{
type: 'memory'
},
reader: {
type:'json',
rootProperty: 'data'
//messageProperty:'message'
},
autoLoad:false
}
}
});
Please, I have been stuck on this for far too long. Please need help?
Let me summarize:
What I want to do is authenticate a user, get user details and store it somewhere databind to the user data in a viewModel and a view (in this case button text)
Thank you

In any view controller where the view has a view model, or a component that has a view model assigned, you can use getViewModel(). So:
Ext.define('MainViewModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.main'
});
Ext.define('MainViewController', {
extend: 'Ext.app.ViewController',
alias: 'controller.main',
launch: function() {
ExtRemote.HWLogin.loginStatus('', function(result, event) {
if(result.success){
this.getViewModel().set('currentUser',
Ext.create('User', result.data.user));
}
});
}
});
Ext.define('MainView', {
extend: 'Ext.Container',
viewModel: 'main',
bind: { title: '{currentUser.username}' }
});
After getting the login result, the currentUser is set on the view model and it becomes available for use in the view.

Related

Can I define a function inside ViewModel and call from Controller in EXT JS

Current scenario is I have data manipulation function inside a class and I call this function when I get data from REST service inside my controller loadData function. Then I update the store of my viewModel.
Now I was wondering Is their a way by which I can concentrate the data manipulation function and store update to view model and from controller I call viewmodel function pass the data from rest service.
Yes you can define function inside of viewmodel and call from controller.
In this FIDDLE, I have created a demo using view-model and controller. I hope this will help you or guide you to achieve your requirement.
Code Snippet
Ext.application({
name: 'MYDEMO',
launch: function () {
Ext.define('FormController', {
extend: 'Ext.app.ViewController',
alias: 'controller.formcntr',
//this will fire on get data button tap
onGetDataButtonTap: function (btn, e, eOpts) {
this.getViewModel().doGetData();
},
//this will fire on set data button tap
onSetDataButtonTap: function (btn, e, eOpts) {
this.getViewModel().doSetData();
}
})
Ext.define('MyViewModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.myViewModel',
//For setting data inside of viewmodel or somthing diffrent opetraion
doSetData: function (data) {
Ext.Msg.alert('Success', 'doSetData method of ViewModel, called from Controller/view');
//set data from here
//or you can put your logic here whatever you want
//Depend on your requirement
},
//For getting data inside of viewmodel or somthing diffrent opetraion
doGetData: function () {
Ext.Msg.alert('Success', 'doGetData method of ViewModel, called from Controller/view');
//return data from here
//or you can put your logic here whatever you want
//Depend on your requirement
}
});
Ext.create({
xtype: 'panel',
title: 'Users Profile',
fullscreen: true,
layout: 'vbox',
controller: 'formcntr',
viewModel: {
type: 'myViewModel'
},
tbar: [{
text: 'GET Data',
handler: 'onGetDataButtonTap'
}, {
text: 'SET Data',
handler: 'onSetDataButtonTap'
}],
renderTo: Ext.getBody()
});
}
});

How to bind correctly a formula with a store in Sencha ExtJs v6?

Here is a configuration for the formula:
formulas: {
//this binding with the store did not work :(
countDeactivatedVehicles: {
bind: {
bindTo: "{organizationCars}",
deep: true,
},
get: function (store) {
return store.query("isCarActive", false).getCount();
}
}
}
(currently now the count that we want is only displayed once initially meaning that on load it works ok)
When the models inside the store organizationCars have an attribute updated the binding does not work, the store is not alerted that its models have been updated.
What ideally should happen is when the model gets updated the event is propagated to the store so that the store knows that is changed. This way the binding would work (?) and the formula would get calculated.
Deepbinding, does not bind that deep.
Here is the answer to your question: Fiddle
I got it working in there.
But - personally - I would go with Theo's idea, because deep binding, is a lot of overhead.
I don't think this is actually possible using formulas, but you can do using events.
by listening to load datachanged and update events you can be notified of any changes to the store, from here you can do what you would do in a formula and manually set on the ViewModel.
This fiddle shows the solution best: https://fiddle.sencha.com/#view/editor&fiddle/1qvf
Store
Ext.define('Fiddle.Store', {
extend: 'Ext.data.Store',
alias: 'store.test',
listeners: {
load: 'storeUpdate',
update: 'storeUpdate',
datachanged: 'storeUpdate'
},
fields: [{
name: 'include',
type: 'bool'
}]
});
ViewModel
Ext.define('Fiddle.StoreBinderViewModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.storebinder',
stores: {
teststore: {
type: 'test'
}
},
data: {
includedTotal: 0
}
});
Controller
Ext.define('Fiddle.StoreBinderController', {
extend: 'Ext.app.ViewController',
alias: 'controller.storebinder',
storeUpdate: function (store) {
var recs = store.query('include', true);
this.getViewModel().set('includedTotal', recs.length)
}
});

ExtJS5 ViewController Listeners Not Firing

I have the following store and ViewController:
Ext.define('WebApp.store.PraDataStore',{
extend: 'Ext.data.Store',
storeId: 'pradatastore',
model: 'WebApp.model.PraDataModel',
sorters: 'practicename'
});
Ext.define('WebApp.controller.admin.PraDataController',{
extend: 'Ext.app.ViewController',
alias: 'controller.pradatactrl',
requires:['WebApp.view.admin.PraDataGrid','WebApp.view.admin.PraDataForm'],
config: {
listen:{
store: {
'#pradatastore':{
load: 'selectPraRecord',
add: 'addPraRecord'
}
}
}
},
selectPraRecord: function(store,record){
console.log('Loaded');
},
addPraRecord: function(store,record){
console.log('Added');
}
});
And I am unable to figure out why the listeners for the store are not firing. The store loads but does not fire the indicated method. Any help would greatly be appreciated.
So I assume the view using this view controller is created before the store loads?

Why the refs to itemId cannot trigger the initialize event in Sencha Touch?

This is the controller code:
Ext.define('XXX.controller.XXX', {
extend: 'Ext.app.Controller',
config: {
views: ['CustomView','CarouselView'],
refs: {
custom: "carouselview #customid"
},
control: {
custom: {
initialize : function() {
alert("it's loading")
}
}
}
},
launch: function(){
Ext.Viewport.add(Ext.create('XXX.view.CustomView'));
console.log(this.getCustom()) // ——> This works, it is not undefined
}
});
and this is the carousel view code:
Ext.define('XXX.view.CarouselView', {
extend: 'Ext.Carousel',
xtype: 'carouselview',
defaults: {
styleHtmlContent: true
},
config:{
direction: 'horizontal',
items: [
{
xtype: 'customview',
itemId: 'customid'
}
]
}
});
Now it's the customview :
Ext.define('XXX.view.CustomView', {
extend: 'Ext.Panel',
xtype: 'customview',
config: {
tpl: XXX
}
});
in the controllers's launch function, it can log the right value, but the initialize event can't be triggered.
And if i change refs to { custom: "customview" }, the initialize event can be triggered.
IMHO you (and someone answered below) misunderstand the use of itemId config.
Here is the difference between id and itemId:
id is the global identifier of a component. It can be used directly as a selector in Ext.ComponentQuery class which refs uses behind the scene. So if you want something like "carouselview #customid", you have to use id instead of itemId.
itemId is the global identifier within a class from which the component derives from. For example, assume that you have an Ext.Button with itemId: "myCustomButton", then you can have access to it via this refs: button#myCustomButton (please note that there's no space between them). This way, Ext.ComponentQuery first looks for all components xtyped button, then find the instance with that itemId.
So, if you want to use some string as "first-class" selector, you will have to use id. If you want to use itemId, you may want to always include its xtype before the itemId. Therefore, 2 possible solutions are:
First solution (still use itemId): custom: "carouselview customview#customid"
Second solution: keep your refs, but change #customid from itemId to id
Hope this helps.
UPDATE:
Just figured out that you are trying to initialize on something that get's the itemId on initialize :) Sorry, took me some time.
Basically the fireEvent('initialize') has already been in the past when you are trying to listen to it in the controller.
Use the xtype to initialize or simply:
Ext.define('XXX.view.CustomView', {
extend: 'Ext.Panel',
xtype: 'customview',
config: {
tpl: XXX
},
initialize: function() { // good way to use initialize inside the view, as it belongs to the view and there is not user input handled
}
});
OR
Ext.define('XXX.controller.XXX', {
extend: 'Ext.app.Controller',
config: {
views: ['CustomView','CarouselView'],
refs: {
custom: ".carouselview .customview" // --> HERE use this
},
control: {
custom: {
initialize : function() {
alert("it's loading") // Yeah, now you are getting here
}
}
}
},
launch: function(){ // --> this will be the same as if you are placing it in app.js launch
Ext.Viewport.add(Ext.create('XXX.view.CustomView')); // --> here the initialize happends and this.getCustom() does not yet exists
console.log(this.getCustom()) // ——> here this.getCustom() exists
}
});

Creating Accordion layout items from datastore in extjs

I have a Panel whose layout is accordin. I have a datastore which gets the data from server in json format and maps to a model. The data I get is a list of that model. Now in my view, I need to access the store and get all the records, and for each record I need to create a Panel and add it to the parent Panel.
My Store
Ext.define('NOS.store.ResultGroupsStore', {
extend: 'Ext.data.Store',
requires : ['NOS.model.ResultGroup'],
model: 'NOS.model.ResultGroup',
fields:['groupName'],
alias: 'widget.resultStore',
// autoLoad: true,
proxy: {
type: 'ajax',
url: 'showResult.nos',
reader: {
type: 'json'
}
}
});
My View
Ext.require('Ext.panel.Panel');
Ext.define('NOS.view.ResultView' ,{
extend: 'Ext.panel.Panel',
alias:'widget.results',
title: 'My title',
layout:'accordion',
items:null,
initComponent : function() {
console.log("reached in view initialise");
results = Ext.create('NOS.store.ResultGroupsStore');
results.load();
results.each(function(aResultGroup, index) {
console.log('Record ' + index);
});
console.log("End in view initialise");
this.callParent(arguments);
},
});
But it never enters the loop above. I am sure the data is loaded properly to the store because when I use a grid.Panel and map the columns it renders the data.
Please help!!
Store loading is asynchronous, when you you're iterating over the store, it hasn't loaded yet so the store is empty. You need to do it in the store callback.
Ext.require('Ext.panel.Panel');
Ext.define('NOS.view.ResultView' ,{
extend: 'Ext.panel.Panel',
alias:'widget.results',
title: 'My title',
layout:'accordion',
items:null,
initComponent : function() {
var results = this.results = Ext.create('NOS.store.ResultGroupsStore');
results.on('load', this.onStoreLoad, this, {
single: true
});
results.load();
this.callParent(arguments);
},
onStoreLoad: function() {
this.store.each(function(rec){
});
}
});

Resources