Passing data to another view from controller and set a label's value in sencha touch - extjs

I have a controller, and I want to pass a simple string value to the next View.
For that, I am creating the View like this.
var nextView = Ext.create('MyApp.view.NextView', {
content: 'value'
});
Ext.Viewport.add(nextView);
Ext.Viewport.animateActiveItem(nextView, {
type: 'slide',
direction: 'left'
});
On the NextView, I have a label and I want to set the HTML property of the label to the value that I am passing from the controller. ie. value.
My NextView looks like this.
Ext.define('MyApp.view.NextView', {
extend: 'Ext.form.Panel',
config: {
content: 'null',
items: [{
xtype: 'label',
html: 'value'
}]
}
});
I am not sure how to proceed from here. I can't have the NextView as a form. I just need to pass one string value in this situation.
What's the best way to achieve this?

Use initialize method to access config data like this:
Ext.define('MyApp.view.NextView', {
extend: 'Ext.form.Panel',
config: {
content: 'null',
items: [
{
xtype: 'label',
html: 'value'
}
]
},
initialize : function(){
this.callParent();
var val = this.config.content;
this.down('label').setHtml(val);
}
});
PS Feel free to use your favourite selector in down function

I know the question has been answered. But I just digged up a pretty natural way to pass data from controller to a view (using view's constructor). I use this in my integration of web desktop to my app.
In controller, pass data to the constructor of the view as followed:
loiTab = Ext.create('Iip.view.giips.admission.DetailedLoiTab', {closable: true, selectedLoiData: selected[0].data});
In the view, spin up a constructor as followed:
constructor: function(selectedLoiData) {
Ext.applyIf(this, selectedLoiData);
this.callParent();
},
The following method lives in the same file as the constructor. You can access selectedLoiData from any where in the view the constructor lives as followed:
initComponent: function(){
console.log(this.selectedLoiData);
}

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()
});
}
});

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
}
});

getRootNode() is not a function

I try to develop an app with MVC architecture. I've the following Controller code:
Ext.define('PM.controller.Projects', {
extend: 'Ext.app.Controller',
models: ['Project'],
stores: ['Projects'],
views: [
'projects.Tree',
'Toolbar',
],
init: function(config) {
var tree = this.getProjectsTreeView();
var rootNode = tree.getRootNode();
console.log(rootNode);
this.callParent(config);
}
});
And this view code:
Ext.define('PM.view.projects.Tree', {
extend: 'Ext.tree.Panel',
xtype: 'projectsTree',
title: 'Projects',
hideHeaders: true,
root: {
text: "Projekte"
}
});
It try to get the root node from my tree view in the controller but I get the error that getRootNode() is not a valid function in my controller. Can anybody tell me why I get this error? My target is to add new children to this root node from an ajax request.
Thanks
The methods Ext generates for each string in the views array return constructors that can be used to create the respective views. That seems bizarre, but that's how it is.
If you want to access the actual view component, you'll need to create a ref for it. Your init method should not assume that the view exists yet. It's very likely that it won't since the controller's init method is called before the application's launch method which is probably where all the views are getting added to the page.
You want to put your logic in the controller's onLaunch template method which is called after the application has been launched and your view has been added.
Ext.define('PM.controller.Projects', {
extend: 'Ext.app.Controller',
refs: [{
ref: 'projectsTreeView',
selector: 'projectsTree'
}],
init: function() {
// It's safe to add selectors for views that don't exist yet.
this.control(/*...*/)
},
onLaunch: function(config) {
var tree = this.getProjectsTreeView();
var rootNode = tree.getRootNode();
console.log(rootNode);
}
});
If this doesn't work, that means you aren't actually adding your view anywhere. One place you could add it is in the application's launch method. Something has to add the treeview.
Ext.application({
// ...
views: ['projects.Tree']
launch: function() {
Ext.create('Ext.container.Viewport', {
layout: 'fit',
items: [new this.getProjectsTreeView()]
});
}
});
So the chronology of events is this:
Application#constructor
Controller#constructor
Controller#init (can't assume the view exists)
Application#onBeforeLaunch
Application#launch (view is now added)
Controller#onLaunch (do something with the view that is now available)
Also, your view alias may need to be 'widget.projectsTree' not just 'projectsTree'.

In ExtJS components how to forward config: {} items to sub components

I am trying to write a reusable item selection panel where the user has a grid with items he can choose from and a small text field that he can use to filter the content of the grid. Right now the (simplified) view code looks like this and works.
Ext.define('MyApp.view.items.ItemSelectorPanel', {
extend: 'Ext.panel.Panel',
require: 'MyApp.view.items.SimpleItemGrid',
alias: 'widget.ItemSelectorPanel',
layout: 'form',
config: {
itemStore: false
},
constructor: function(config) {
this.initConfig(config);
this.superclass.constructor.call(this, config);
this.add([
{
fieldLabel: 'Filter',
name: 'filter'
},
{
xtype: 'SimpleItemGrid',
collapsible: true,
store: this.getItemStore()
}
]);
return this;
}
});
As you can see the ItemSelectorPanel uses the config property to expose an interface where the calling site can specify which item store to use.
Calling site (in this case the panel is added to a TabPanel):
var panelToAdd = {
xtype: 'panel',
title: 'New Selection',
closable: true,
padding: 10,
items: [{
title: 'Select node',
xtype: 'ItemSelectorPanel',
itemStore: itemStore
}]
};
Now, I love the declarative style of ExtJS 4 and how it helps to follow the MVC pattern. I would prefer to have the least amount of code possible in the views. Unfortunately this does not work:
Ext.define('MyApp.view.items.ItemSelectorPanel', {
/* ... same as above ... */
constructor: function(config) {
this.initConfig(config);
this.superclass.constructor.call(this, config);
return this;
},
items: [
{
fieldLabel: 'Filter',
name: 'filter'
},
{
xtype: 'SimpleItemGrid',
collapsible: true,
store: this.getItemStore // <-- interesting part
}
]
});
Is there a way to expose the config of a nested/sub component via the config property of the parent property in a declarative manner?
First something in general
Never add an object outside a function within a class definition unless you exactly know what you are going to do. Cause if you do so all instances will share the same instance of that object. I think I do not need to mention where this leads to...
If you have a need to place a object there you should clone it within the constructor.
To your code
I dunno what this.initConfig(config); does but the config variable is not the one from your class, it is the one from the constructor argument. I recommend you also to use initComponent() for initialization instead of the constructor() unless you have a defined need for using the constructor, which in your case you don't seem to have.
Also a 'config' is not forwarded cause it don't get executed up->bottom but bottom->up where a config get's hand up and all other properties are (already) inherited.
I still do not exactly know what your goal is, therefore I cannot give you any advice how you should do this but I can say for sure that the way you do it will lead to problems.
Edit
I still not sure that I have fully understand your needs but the following should work (if you need the listeners too you might take a look at the Ext.util.Bindable mixin)
Ext.define('MyApp.view.items.ItemSelectorPanel', {
extend: 'Ext.panel.Panel',
require: 'MyApp.view.items.SimpleItemGrid',
alias: 'widget.ItemSelectorPanel',
layout: 'form',
initComponent: function() {
// Initialize the store (might be a instance or a storeId)
var store;
if (this.itemStore) {
store = Ext.data.StoreManager.lookup(store);
}
this.itemStore = store || null;
// Add is not valid (at least not before the parent inits are executed)
this.items = [{
fieldLabel: 'Filter',
name: 'filter'
}, {
xtype: 'SimpleItemGrid',
collapsible: true,
store: this.getItemStore()
}];
this.callParent(arguments);
},
getItemStore: function() {
return this.itemStore;
}
});
No, you can't do it in the way you've described. The reason is pretty simple, let's take this as an example:
Ext.define('MyClass', {
someProp: this.foo(),
foo: function(){
return bar;
}
});
Here, we call the define() method and we pass it an object as the configuration. As such, the whole object (including the call to foo()) is evaluated before it's even passed to define, so the class/method doesn't even exist at that point.
Even if you could do that, here's also the complication that foo is an instance method on the class, but the way you're attempting to call it is as though it's a static method.
So, the answer is, you'll need to use some kind of method to do so, initComponent is typically preferred over the constructor.
You can define items in declaration of your class but you cannot call any method from your class at time of declaration. To solve it, define only items without store and than use initComponent method to set store for your view.
I didn't see an answer that addressed the original question. Here is what I've found to work ...
Creating an instance of myClass, passing in a config 'foo' with value 'bar'
var myClassInstance = Ext.create('MyApp.view.myClass', {
foo: 'bar'
});
myClass is defined as follows :
Ext.define('MyApp.view.myClass', {
extend: 'Ext.container.Container',
alias: 'widget.myclass',
config: {
foo: 'defaultVal'
},
constructor: function(configs) {
this.callParent(arguments); //create class, calls initComponent
var try1 = getFoo(); //try1 is 'defaultVal'
this.initConfig(configs); //initializes configs passed in constructor
var try2 = getFoo(); //try2 is 'bar'
},
initComponent: function() {
//myClass declaration here ...
this.callParent();
}

extJS: Adding grid.Panel from Controller to View causes application to hang (MVC)

I am trying to dynamically create grid.Panels and add them to my View, since I don't know have many "Views" I need before I load the data. For example, I have a number of people in different groups, once I load the data, I want to create a grid.Panel for each group and put the correct people in it.
The problem is that my application hangs when I do it (probably because the Store is being loaded recursively)
How do I add a grid.Panel to my View with data from a Store without it hanging?
My Controller:
Ext.define('NG.controller.Navigation', {
extend: 'Ext.app.Controller',
refs: [{
selector: 'group',
ref: 'groupPanel'}
],
stores: ['Groups'],
init: function() {
this.control({
'navigation': {
itemdblclick: this.onNavigationSelection
}
});
},
onNavigationSelection: function(view, record, item, index, eventobj, obj) {
var groupsstore = this.getGroupsStore();
var group1 = Ext.create('Ext.grid.Panel', {
store: groupsstore,
title: 'Group 1',
columns: [
{header: 'Name', dataIndex: 'name'},
{header: 'Mail:', dataIndex: 'mail'}
]
});
groupsstore.load();
this.getGroupPanel().add(group1);
}
});
My View:
Ext.define('NG.view.Group', {
extend: 'Ext.panel.Panel',
alias: 'widget.group',
store: 'Groups',
initComponent: function() {
this.callParent();
}
});
And my Store (not sure if it is needed):
Ext.define('NG.store.Groups', {
extend: 'Ext.data.Store',
requires: 'NG.model.Person',
model: 'NG.model.Person'
});
Best regards and thank you in advance!
Andreas
After walking through each reference I could not find any errors in the code. However I found a bug report about a similar problem:
http://www.sencha.com/forum/showthread.php?141804-4.0.5-Grid-Uncaught-RangeError-Maximum-call-stack-size-exceeded
I downloaded the Framework last week, and there was an update a few days ago, which solved this bug and my problem as well.
Thank you for your help!
The store.load() event is asynchronous.
Try switching the add panel and load store events around:
this.getGroupPanel().add(group1);
groupsstore.load();
The other thing is it doesn't look like you are passing anything to the store to load it. So you can just autoload it and have the data ready ahead of time.

Resources