I have a MVC app built with extJS 4.
I want to disable a docked button in a grid panel from a controller
Here is my grid panel view:
Ext.define('SDI.view.MissionsGridPanel', {
extend: 'Ext.grid.Panel',
alias: 'widget.missionsGridPanel',
width: 688,
title: 'Missions',
store: 'MissionsStore',
tbar:[
{
text:'Delete mission',,
icon: '/images/delete.png',
itemId: 'removeMissionButton',
disabled: true,
action :'delete'
}
]...
Here is my controller :
Ext.define('SDI.controller.MissionsController', {
extend: 'Ext.app.Controller',
views: ['SDI.view.MissionsGridPanel'],
refs: [
{
selector:'missionsGridPanel',
ref:'missionsGridPanel'
},
{
selector:'missionsGridPanel button[action=delete]',
ref:'missionsGridPanelToolbarDelButton'
}
],
init: function() {
this.control({
'missionsGridPanel': {
selectionchange: this.onMissionSelect
}
})
},
onMissionSelect: function(pTarget,pRecord,pOptions){
console.log("Mission is selected")
this.getMissionsGridPanelToolbarDelButton().setDisabled(false);
}
});
I don't understand why this doesn't work.
"Mission is selected" is logged but the button remains disabled.
Here is how to troubleshoot this -
Go to the Firebug console, type this:
Ext.ComponentQuery.query('missionsGridPanel button[action=delete]')
and see if anything is being returned. I would recommend installing Illuminations for Developers firebug plugin to further help you figure out whats what on your page.
I am not sure why it's not working, but it works fine if you call it by itemid:
selector: 'missionsGridPanel #removeMissionButton'
Related
I need to add a custom button to CKEditor 4.6.2 instance without plugin.
I've tried solution suggested at similar question How to add a custom button to the toolbar that calls a JavaScript function?
The difference is that I don't want to replace existing instance, but instead modify it after it's initialised. Like here: http://jsfiddle.net/paragonid/8r4gk45n/1/
CKEDITOR.replace('container', {
on: {
instanceReady: function( evt ) {
console.log('instanceReady', evt)
evt.editor.addCommand("mySimpleCommand", {
exec: function(edt) {
alert(edt.getData());
}
});
evt.editor.ui.addButton('SuperButton', {
label: "Click me",
command: 'mySimpleCommand',
toolbar: 'insert',
icon: 'https://avatars1.githubusercontent.com/u/5500999?v=2&s=16'
});
}
}
});
But button doesn't appear in this case.
I also faced the same issue, this is how I resolved mine-
var editor = CKEDITOR.replace(ck, {
toolbar: [['Source','-','Preview','Print'],['UIColor','Maximize','ShowBlocks'],
['Cut','Copy','Paste','PasteText','PasteFromWord','-','Undo','Redo','RemoveFormat','-','Link','Unlink','Anchor'],
['Bold','Italic','Underline','Strike','Subscript','Superscript','RemoveFormat'],['Link','Unlink','Anchor'], '/',
['NumberedList','BulletedList','-','Outdent','Indent','-','Blockquote','CreateDiv','-','JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock','-','BidiLtr','BidiRtl'],
['Styles','Format','Font','FontSize'],['TextColor','BGColor'],'/',
{name: 'insert', items:['InsertCustomImage','Flash','Table','Iframe','HorizontalRule','Smiley','SpecialChar','PageBreak']}]
});
editor.addCommand("insertImgCmd", {
exec: function(edt) {
helper.showdlg(component);
}
});
editor.ui.addButton('InsertCustomImage', {
label: "Insert Image",
command: 'insertImgCmd',
toolbar: 'insert',
icon: 'https://avatars1.githubusercontent.com/u/5500999?v=2&s=16'
});
While setting the toolbar, I inserted a custom command name "InsertCustomImage".
Now while creating new button below, set the same name as "InsertCustomImage" in addButton function.
Are there other events that can be registered with dojo/form/Select, except onChange?
I'd need to execute a callback function every time user selects an option, even though he selects the same option as it was selected last time. The options I have tried: onSelect, onClick did not work.
var spatialSelectionStore = new Memory({
data: [
{ label: "Rectangle", id: "RECT" },
{ label: "Polygon", id: "POLY" },
{ label: "Circle", id: "CIRC" },
{ label: "Freehand", id: "FREE" }
]
});
var os = new ObjectStore({ objectStore: spatialSelectionStore });
spatialQuerySelect = new Select({
id: "selectionType",
style: { width: "100px" },
store: os,
onChange: activateDrawTool
}, "cp_selectByShapeId");
spatialQuerySelect.startup();
I found a way to do this, and while it may not be the best way to do it, it seems to work.
I set up an aspect to fire a function after the Select._setValueAttr function executes, which is fired by the widget every time you click on either the menu drop-down or a drop-down item. Because of this, I added a check to make sure the function callback only fires when you click on a menu item (i.e. after the menu has closed). I also had to delete the onChange callback you added to Select manually, as this interfered with the aspect.
HTML
<div id="foo"></div>
JavaScript
require(["dojo/aspect", "dojo/store/Memory", "dijit/form/Select", "dojo/data/ObjectStore", "dojo/dom-construct", "dojo/dom", "dojo/aspect"], function(aspect, Memory, Select, ObjectStore, domConstruct, dom, aspect) {
var spatialSelectionStore = new Memory({
data: [
{ label: "Rectangle", id: "RECT" },
{ label: "Polygon", id: "POLY" },
{ label: "Circle", id: "CIRC" },
{ label: "Freehand", id: "FREE" }
]
});
var os = new ObjectStore({ objectStore: spatialSelectionStore });
spatialQuerySelect = new Select({
id: "selectionType",
style: { width: "100px" },
store: os
}, "cp_selectByShapeId");
spatialQuerySelect.startup();
aspect.after(spatialQuerySelect, "_setValueAttr", function() {
if(spatialQuerySelect.dropDown.isShowingNow === false) {
alert(spatialQuerySelect.get('value'));
}
});
domConstruct.place(spatialQuerySelect.domNode, dom.byId("foo"), "first");
});
Fiddle
Aspects can be very powerful, but if you use too many and rely on them too heavily, you can end up with a horrible mess of spaghetti code, so I recommend you use them sparingly, and only when necessary.
In case you're not familiar with what they do, you can tell an aspect to fire before, after, or around another method, and the aspect will "listen" to that method being fired and behave appropriately with your function callback. Further documentation.
spatialQuerySelect.dropDown.on("execute",function() {
alert(spatialQuerySelect.get('value'));
});
this would also work for all option.
onExecute: function(){
// summary:
// Attach point for notification about when a menu item has been executed.
// This is an internal mechanism used for Menus to signal to their parent to
// close them, because they are about to execute the onClick handler. In
// general developers should not attach to or override this method.
// tags:
// protected
},
I'm trying to do is figure out how to pass in variables to a view from a controller.
For example, let's say I have a login screen where I want to display the application version and the some other custom device information. How would I go about passing that info into the view?
Ext.define('MyApp.view.Login', {
extend: 'Ext.form.Panel',
xtype: 'loginform',
config: {
items: [
{
xtype: 'label',
cls: 'appVersion',
html: 'Version #:' + versionNumber
}
]
}
});
Also how much different would it be if I used tpl instead of html ?
Thanks for any help!
You can always pass data during view creation like this:
var loginPanel = Ext.create('MyApp.view.Login', {
ver : versionNumber // any value or data you want to pass
});
for that you might have to define ver in your view's config
Ext.define('MyApp.view.Login', {
extend: 'Ext.form.Panel',
xtype: 'loginform',
config: {
ver : '', // Initialize with empty string
items: [
{
xtype: 'label',
cls: 'appVersion',
html: 'Version #:' + versionNumber
}
]
}
});
Once created with required value you can add it anywhere you want
Ext.Viewport.add(loginPanel);
You can always use PhoneGap (Cordova) for this: http://docs.phonegap.com/en/2.3.0/cordova_device_device.md.html#Device
Also, using html or tpl is fine.
I'm beginning development of an app in extjs. I'm using the MVC approach, as provided in the extjs documentation.
I have some dynamic data which needs to present the user with a set of accordion controls. I've got the data in a store, but I do not know how to dynamically create the accordion items (unlike grid panels, there doesn't appear to be a store data method).
Here is my current accordion view code - with static items:
Ext.define('BP.view.induction.LeftPage', {
extend: 'Ext.Panel',
alias : 'widget.leftpage',
title: "Left Page",
layout: {
type: 'accordion',
align: 'stretch'
},
layoutConfig: {
// layout-specific configs go here
titleCollapse: true,
animate: true,
activeOnTop: true
},
items: [{
xtype: 'panel', // fake hidden panel, so all appear collapsed
hidden: true,
collapsed: false
},{
xtype: 'panel',
title: 'Panel 1',
html: 'Panel content!'
},{
xtype: 'panel',
title: 'Panel 2',
html: 'Panel content!'
},{
xtype: 'panel',
title: 'Panel 3',
html: 'Panel content!'
}]
});
Any guidance on how to achieve the above would be appreciated, thank you.
[Edit] In response to sra's request, here is my controller:
Ext.define('BP.controller.Induction', {
extend: 'Ext.app.Controller',
views: [
'induction.Binder'
],
stores: [
'Sections',
'Categories',
'Tasks'
],
init: function() {
console.log('Initialized Induction!');
}
});
I should note here that this controller loads a parent view, which in turn loads the LeftPage view - I'm not sure if this creates any scoping issues. Furthermore, as you can see, more than one store is loaded.
You can do like this (untested example with some tweaks)
Ext.define('BP.view.induction.LeftPage', {
extend: 'Ext.Panel',
alias : 'widget.leftpage',
title: "Left Page",
layout: null,
layoutConfig: null,
store: null,
attentive: true,
initComponent: function() {
var me = this;
// begin edit
// only set the store if is is not already defined
me.store = me.store ? me.store : Ext.StoreMgr.lookup('Sections'); // you may change this to any storename you want
// end edit
me.layout = { // don't set objects directly in class definitions
type: 'accordion',
align: 'stretch'
};
me.layoutConfig = { // dont set objects directly in class definitions
titleCollapse: true,
animate: true,
activeOnTop: true
};
me.callParent(arguments);
if (me.attentive) {
me.store('load', me.onRebuildContent, me);
if (me.store.count() == 0)
me.store.load();
} else {
me.buildContent();
}
},
buildContent: function() {
var me = this;
function addItem(rec) {
me.add({
xtype: 'panel',
title: rec.get('titleProperty'),
html: rec.get('bodyProprty')
});
};
me.store.each(addItem);
},
onRebuildContent: function() {
var me = this;
me.removeAll();
me.buildContent();
}
});
Your store will need at least two properties; one for the title and one for the content. And the store need to be loaded before you should instantiate this. But that can easily be done within your controller.
Edit based on comment and new OP info:
Well your view is a bit out of control of the controller. So I recommend you to simply use the StoreManager to receive a valid instance (I've edited the code, I just didn'T know the correct store to use). The StoreManager will know about the store as long as you list him within a controller (StoreManager is capable of much more, but that is all you need to know at the moment). For a further release you could also use the mixin bindable which would manage a storebinding more clean and enables you to update your accordion after the store receives new data (get updated)
Edit for readability
I've just cleaned it up a bit and included a switch param attentive which would allow you to use this component as directly bound to a store, reacting on all load events or as a sort of static one where the store should already be loaded. All in all this should give you a start without making it to complex.
i am wondering about the 'refs' attribute of Sencha Touch class 'Ext.app.Controller'.
I saw a video tutorial where a simple contactForm was built. No i've tried to build a contact form for my app and i get an error: 'Uncaught TypeError: Object [object Object] has no method 'getContactForm''
Here's my controller
Ext.define('MyFirstApp.controller.Main', {
extend: 'Ext.app.Controller',
views: ['Viewport', 'Home'],
refs: [
{
ref: 'contactForm',
selector: '#contactForm'
}
],
init: function() {
this.control({
'button[action=submitContact]': {
tap: 'submitContactForm'
}
});
},
submitContactForm: function() {
var form = this.getContactForm();
form.submit({
url: 'contact.php'
});
}
});
I guess it's something wrong with the 'refs', in the video that guy said the "getContactForm" method will be created because of the "ref" attribute of "contactForm" but it doesn't. What am i doing wrong here?..Thanks for help!
The refs attribute property changed from Sencha Touch 2.0 developer preview version to beta/final version. So, what you wrote were correct for dev preview but presently it just name value pair. For your case:
refs: {
contactForm: '#contactForm'
}
I agree with jeremygerrits, I can't be sure that's the correct syntax for defining refs.
Based on the documentation, I would rather do it like this:
Ext.define('MyFirstApp.controller.Main', {
extend: 'Ext.app.Controller',
views: ['Viewport', 'Home'],
config: {
refs: {
contactForm: '#contactForm'
}
}
init: function() {
this.control({
'button[action=submitContact]': {
tap: 'submitContactForm'
}
});
},
submitContactForm: function() {
var form = this.getContactForm();
form.submit({
url: 'contact.php'
});
}
});
See also: http://docs.sencha.com/touch/2-0/#!/guide/controllers
It looks as though you may have the refs configured wrong. Here's a simple controller:
Ext.define('App.controller.Main', {
extend: 'Ext.app.Controller',
config: {
refs: {
main: 'mainpanel'
}
}
});
mainpanel is an xtype or could be a css selector and main will give you getMain() like what was talked about in the video.