How to catch imageclick event in controller of extjs4 - image

I am working in extjs4. i have extjs view as-
Ext.define('Balaee.view.kp.Word.SearchWord', {
extend:'Ext.form.Panel',
id:'WordId',
alias:'widget.SearchWord',
bodyPadding: 30,
defaults:{
margin:'0 20 0 70'
},
layout: {
type: 'hbox'
},
items:[
{
xtype:'textfield',
fieldLabel:'Enter the Word:',
name:'Word',
// height:30,
border:false,
allowBlank:false,
emptyText: 'Enter the word',
id:'wordtext'
},
{
xtype: 'image',
width: 30,
height: 22,
src: 'http://www.asien-news.de/wp-content/uploads/new-york.jpg',
}
],});
I want to call controller's function on click of above image. So how to catch image click event in controller?

You can use listeners propetry from Observable class;
A config object containing one or more event handlers to be added to
this object during initialization. This should be a valid listeners
config object as specified in the addListener example for attaching
multiple handlers at once.
Simply bind it on the underlying element, like this:
listeners: {
el: {
click: function() {
Ext.Msg.alert("Image clicked");
}
}
}
here is a example.

Related

ExtJS: How to let user enter a value in Combobox that is not in store

I have a combobox which is a list of various addresses. When any address is selected, the select event plots this address on map. I want to change this program in such way that, if a user enters an address which is not a part of the Combo store, this address should still be plotted on the map. I do not require to modify the combo store. How can this be done? What event listener can trigger such event? Do I need to swap to a textfield?
{
xtype: 'combobox',
name: 'address1',
style: {
marginLeft: '15px'
},
store: Ext.create('MyStore'),
valueField: 'address',
displayField: 'address',
triggerAction: 'all',
emptyText: 'Select Address',
typeAhead: true,
minChars: 2,
typeAheadDelay: 100,
queryMode: 'remote',
width: 300,
queryParam: 'searchAddress',
hideTrigger:true,
listeners: {
select: function(combo, records, eOpts){
//Plot the address from records[0].data.address
}
}
}
The user can press enter key to indicate that the address is either
selected or types in. Currently, the specialkey event can't always
capture it because on enter rather than taking the typed in value, it
selects the first value in store
specialkey won't be captured indeed if the dropdown list is shown. This is because the event is simulated on keydown which the dropdown list intentionally stops as can be seen here.
Still there are ways to react to user input:
Method 1
Use a custom onFieldMutation method like this:
Ext.define('MyCombo', {
extend: 'Ext.form.ComboBox',
onFieldMutation: function(e) {
if (e.getKey() === e.ENTER) {
// Call address plotting method here
}
return this.callParent(arguments);
}
});
Method 2
Use keyup:
listeners: {
keyup: {
fn: function(e) {
if (e.getKey() === e.ENTER) {
// Call address plotting method here
}
},
element: 'inputEl'
}
}
See both methods in action: https://fiddle.sencha.com/#fiddle/sdf

dijit/form/Select onSelect event

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
},

ExtJS4 dataView - Select node id

I have an ExtJS 4 dataView and i would like to catch the id of a selected node.
It is the first time that i'm using the dataView, then, there are some troubles.
The store is loaded correctly and i see the datas into the view very well. The problem which i'm having, concern the "classic" actions of update and delete, particularly getting the id of a selected item.
For example into a grid i click, then select a record and through a button's pressing i open a window (or other actions) with a loaded form (by sending in AJAX to the store, the id of the selected row) and i update the datas.
I'm not still able to do it with the ExtJS 4 dataView.
Below my dataView:
dataView_player = Ext.create('Ext.Panel', {
id: 'images-view',
frame: true,
collapsible: false,
autoWidth: true,
title: 'Giocatori (0 items selected)',
items: [ Ext.create('Ext.view.View', {
id:'players-view',
store: store_player,
multiSelect: true,
height: 310,
trackOver: true,
overItemCls: 'x-item-over',
itemSelector: 'div.thumb-wrap',
emptyText: 'Nessun giocatore visualizzato',
tpl: [
'<tpl for=".">',
'<div class="thumb-wrap" id="{id}-{name}">',
'<div class="thumb">',
'<img src="/img/players/{picture}" title="{name} {surname}" alt="{name} {surname}" style="">',
'</div>',
'<span class="" style="height:30px;">{general_description}{name} {surname}</span>',
'</div>',
'</tpl>',
'<div class="x-clear"></div>'
],
plugins: [
Ext.create('Ext.ux.DataView.DragSelector', {}),
Ext.create('Ext.ux.DataView.LabelEditor', {dataIndex: 'name'})
],
prepareData: function(data) {
Ext.apply(data, {
name: data.name,
surname: data.surname,
general_description: Ext.util.Format.ellipsis(data.general_description, 15)
});
return data;
},
listeners: {
'selectionchange': function(record, item, index, e) {
var node = this.getNode(record); //this.getNode(record);
console.log(node.get('id'));
}
}
}) ],
dockedItems: [{
xtype: 'toolbar',
items: [{
iconCls: 'delete',
text: 'Cancella Selezionati',
scale: 'medium',
tooltip: 'Per <b>cancellare</b> i giocatori selezionati',
tooltipType: 'qtip',
id: 'delete-player',
disabled: true,
handler: delete_news
}, '-', {
iconCls: 'edit',
text: 'Aggiorna Selezionata',
scale: 'medium',
tooltip: 'Per <b>aggiornare</b> un giocatore selezionato',
tooltipType: 'qtip',
disabled: false,
id: 'update-player',
handler: function(nodes) {
var l = nodes.get('id');
console.log(l);
}
}
}
]
}]
});
Of course, this is a wrong example (because the listeners don't work) but it's just to make an idea.
There are two main things what i would like to do:
1) Catch the id (and other store's fields) of the selected item on the action "selectionchange". Obviously, now it doesn't work because of this: node.get('id'). Of course it's a wrong syntax but make up the idea of my will.
2) Catch the id of the selected item on the handler event of the "update-player" button. As above, the issue is the nodes.get('id'). Further trouble, is how to pass the selected item's features. in handler: function(nodes) { the nodes variable does not assume any value and i don't know how to pass the params from the dataview to the handler function.
I hope that somebody will able to help me.
According to the docs the selectionchange event provides the selection model as well as the array of selected records, so you are probably assuming the wrong parameters in your listener.
Without doing further testing, I think it should be something like this:
listeners: {
'selectionchange': function(selModel, selection, eOpts) {
var node = selection[0];
console.log(node.get('id'));
}
}
Note that you're using multiSelect: true, so it could be more than one record in the selection array.
Answer for second part of the question:
In button handler, you need to get selection model of the view and from it get information about selected records:
handler: function(nodes) {
// find view component
var view = dataView_player.down('dataview');
// get all selected records
var records = view.getSelectionModel().getSelection();
// process selected records
for(var i = 0; i < records.length; i++) {
console.log(records[i].getId());
}
}

Add change event handler for custom Container of ExtJS

I have created a View by extending Ext.container.Container and have given it an alias widget.myCustomView. Since I'm using it in different places.
The view as usual Ext form components like textfield, dataview, etc. Now I adding this view into other view using xtype as follows:
{
xtype: 'myCustomView',
itemId: 'myCustomView'
}
Now, I want to add change event handler such that if any component's change is fired, I can fire the change event of myCustom view. In short, do something like this.
{
xtype: 'myCustomView',
itemId: 'myCustomView',
listeners: {
'change' : function(viewObj, eOpts) {
//do something
}
}
}
How to do it?
Use the relayEvents() method to... well, relay the change event from child fields.
Here's some basic code that does that:
Ext.define('My.Container', {
extend: 'Ext.Container'
,layout: 'form'
,initComponent: function() {
this.callParent(arguments);
// i want to support nested containers
this.parseContainerItems(this);
}
,onItemAdded: function(item) {
if (item instanceof Ext.Container) {
this.parseContainerItems(item);
} else if (item instanceof Ext.form.field.Base) {
this.relayEvents(item, ['change']);
}
}
,parseContainerItems: function(ct) {
if (ct.items) {
ct.items.each(this.onItemAdded, this);
}
}
});
Example usage:
Ext.create('My.Container', {
renderTo: 'ct' // render to a test div
,height: 200
,width: 200
,items: [{
xtype: 'textfield', name: 'foo', fieldLabel: 'Foo'
},{
xtype: 'container'
,items: [{
xtype: 'checkbox', name: 'bar', fieldLabel: 'Bar'
}]
}]
,listeners: {
change: function(item, newValue, oldValue) {
console.log(Ext.String.format('Value of item {0} changed from {1} to {2}', item.name, oldValue, newValue));
}
}
});
Going further...
As I've said my implementation is quite rudimentary since it only supports fields that are added to the container by configuration. If you want to make that component flexible, you'll have to handle fields that are added after the component creation.
For that you'll need to watch the add event of the container to relay from fields that are added after its creation. The doc says that this event bubbles from child containers, but from my tests it does not :-( So (until that's fixed?) you'll also have to watch the add event of child containers.
Here's the updated code for the parseContainerItems() method:
parseContainerItems: function(ct) {
ct.on('add', function(me, item) {
this.onItemAdded(item);
}, this);
if (ct.items) {
ct.items.each(this.onItemAdded, this);
}
}
If you also want to support the possibility of removing fields dynamically, that's when things will go awry... You'd have to implement your own version of relayEvents() because, as far as I know, it is not possible to stop relaying events with the one provided by Ext. Then you'd have to watch the remove event to remove the listeners you've added to child fields and containers.

Extjs create dynamic accordion using store

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.

Resources