Catch change in content of HtmlEditor in ExtJS 4 - extjs

I want to capture whenever the user changes the content of an HtmlEditor in ExtJS 4. I have tried the sync, change, and push events all with no success. Sync seems to be fired whenever focus is gained, change isn't fired, and I can't tell what causes push to be fired.
Can anyone tell which event is fired when the user changes the content of an HtmlEditor?
Thanks
Edit:
I have tried the following code which does not work for me, any ideas?
init: function() {
this.control({
'htmleditor[name="reportHtmlEditor"]': {
render: this.addKeyHandler
}
});
},
addKeyHandler: function(field) {
// This gets called fine on the component render
var el = field.textareaEl;
if (Ext.isGecko) {
el.on('keypress',
function() {
// Do Stuff, which never gets called
}, this, { buffer: 100});
}
if (Ext.isIE || Ext.isWebKit || Ext.isOpera) {
el.on('keydown',
function() {
// Do Stuff, which never gets called
}, this, { buffer: 100});
}
},
For some more information, I am using Firefox to test this, and I got the other information from this post.

It looks like there is textarea used for editing source. This field, like any other in html, fires change event only after blur (HtmlEditor seems to rely on this event). You should probably bind to other event eg keydown and then depending on key pressed, fire appropriate event. You can do it in render handler:
{
xtype: 'htmleditor',
listeners: {
render: function(){
this.textareaEl.on('keydown', function() {
this.fireEvent('sync', this, this.textareaEl.getValue());
}, this, { buffer: 500 });
},
sync: function(sender, html){
debugger;
}
}
}

Related

Ext.form.Panel's beforesubmit listener does not respect return: false when attached via controller

I have a formpanel with a beforesubmit listener, which should prevent the submission if the form is invalid.
Sencha Fiddle availble here:
https://fiddle.sencha.com/#fiddle/3j5l (just comment the beforesubmit: 'onFormBeforeSubmit' line within the controler/panel and inspect the console to see the difference)
The listener is attached via a controller trough the init function like this:
//controller init function
init: function () {
var me = this;
me.listen({
component: {
'formpanel': {
beforesubmit: 'onFormBeforeSubmit'
}
}
});
},
onFormBeforeSubmit: function () {
console.log(arguments);
var me = this, form = me.getView();
console.log('beforesublit event fired');
if (!form.validate()) {
console.log('form is invalid!');
return false;
}
}
And all seems fine - the submit procedure is started, the onFormBeforeSubmit() method is executed, the form is considered invalid, but althought there is a return false statement - the form is submitted to the server.
Then, i tried to attach the listener simply via the listeners config of the panel like this:
//panel definitions...
listeners: {
beforesubmit: 'onFormBeforeSubmit'
}
And then it worked as expected.
As you can see the executed function is the same.
One thing i mentioned is that it receives different arguments - if triggered via the listeners config - it has a 5 arguments. Via controller - they are 4. The 5th one is an obect like this:
beforesubmit: "onFormBeforeSubmit"
scope: "self"
Can someone explain me why is this? Is it a bug or an expected behavior?
And after all - where is the right place to attach the listeners - in the controller or within the view??
Thanks.
First of all, you don't have to do this in init function.
Simply use control block of your viewcontroller like this:
control: {
formpanel: {
beforesubmit: 'onFormBeforeSubmit'
}
},
Please refer the documentation of control, it is much more straightforward to use that.
But it still not enough, and I think you are right, this is a bug. FormPanel's submit actually still using already deprecated function to fire events.
Please try the following override, it should fix this and allows you to use event listeners defined in controllers:
Ext.define('FixPanelEventFiring',{
override: 'Ext.form.Panel',
submit: function(options, e) {
var me = this,
formValues, form;
options = options || {};
formValues = me.getSubmitValues({
enabled: me.getStandardSubmit() || !options.submitDisabled
});
form = me.element.dom || {};
if (this.getEnableSubmissionForm()) {
form = this.createSubmissionForm(form, formValues);
}
options = Ext.apply({
url: me.getUrl() || form.action,
submit: false,
form: form,
method: me.getMethod() || form.method || 'post',
autoAbort: false,
params: null,
waitMsg: null,
headers: null,
success: null,
failure: null
}, options || {});
return me.fireEventedAction('submit',
[me, formValues, options, e],
'doBeforeSubmit',
this,
null,
'after'
);
},
});
Please be sure you include this in your overrides. You can also test this in fiddle, just add it before everything else. I'm not 100% sure it is perfect, I can imagine there are other issues with this, so please test this well.

Ext JS: Window child component hide event

I have a Window that contains several child components (example only contains a Panel). When I hide this Window, I want the child components to do some processing. Is there an event the child components can listen for when the parent is hidden? I tried using hide, disable, and deactivate, but none of them fired.
This is the example code and Fiddle I'm working with:
var myPanel = Ext.create('Ext.panel.Panel', {
title: 'My Panel'
});
myPanel.on('afterrender', function() {
myPanel.el.on('hide', function() {
alert('el hidden');
}, this);
}, this);
myPanel.on('hide', function() { alert('hidden'); }, this);
myPanel.on('deactivate', function() { alert('hidden'); }, this);
myPanel.on('disable', function() { alert('hidden'); }, this);
var myWindow = Ext.create('Ext.window.Window', {
height: 300,
width: 300,
items: [myPanel],
closeAction: 'hide'
});
var button = Ext.create('Ext.button.Button', {
text: 'Toggle Window',
renderTo: Ext.getBody()
});
button.on('click', function() {
if (myWindow.isVisible()) {
myWindow.hide();
}
else {
myWindow.show();
}
}, this);
When the Window gets hidden, I want to enter the event listeners. I even started experimenting with getting the DOM Element, but there's no such event as hide. I realize I can control the processing from the Window, but I'd rather have each component listen for an event and take care of itself autonomously.
Any thoughts?
As far as i know, you cant listen directly to another component's events, although you could do some processing in a controller and accomplish this.
The most similar approach to what you asked that i could come up with was to listen to the hide event in the parent, and fire the same event in the child component.
-working fiddle:
https://fiddle.sencha.com/#fiddle/c74
you could iterate all children and do what you need.

Overriding back button in android - Phonegap Angularjs

I have following as my index.js (used to initialize phonegap)
function onBackKeyDown() {
angular.element('[ng-controller=NavCtrl]').scope().back();
}
var app = {
// Application Constructor
initialize: function() {
this.bindEvents();
},
// Bind any events that are required on startup. Common events are:
// 'load', 'deviceready', 'offline', and 'online'.
bindEvents: function() {
document.addEventListener('load', this.onLoad, false);
document.addEventListener('deviceready', this.onDeviceReady, false);
window.addEventListener("orientationchange", orientationChange, true);
},
onLoad: function() {
},
onDeviceReady: function() {
document.addEventListener("backbutton", onBackKeyDown, false);
}
};
This should technically run the function onBackKeyDown when back button is pressed which it does. I can see the logs in logcat.
This as per the documentation should override the default behavior, but apparently when i click back button it not only fires the function but executes the default behavior as well.
I am taken back to my login screen, whereas the behavior described is something else.
Please can anyone point me to the right direction, and let me know what I am not doing correct.
Not sure if it will do the trick but you could check if the onBackKeyDown function get an event as first parameter. If yes then try something like :
function onBackKeyDown(evt) {
evt.preventDefault();
evt.stopPropagation();
angular.element('[ng-controller=NavCtrl]').scope().back();
}

Backbone event being called multiple times

I'm just getting my feet wet with Backbone, and I think I have an easy problem to solve. I have the following view which is a simple tab that when clicked opens up a panel and when closed goes back to a tab:
myApp.views.Support = {
Form: Backbone.View.extend({
initialize: function () {
this.el = $('#support');
this._ensureElement();
},
render: function () {
if (this.$el.hasClass('support-panel')) {
// close panel
this.$el.empty();
this.$el.removeClass('support-panel');
this.$el.addClass('support-button');
}
else {
// open and populate panel
var template = _.template(myApp.utils.RenderTemplate('support/default'), {});
this.$el.removeClass('support-button');
this.$el.addClass('support-panel');
this.$el.html(template);
}
return this;
},
closePanel: function () {
alert('close event fired');
},
events: {
'click #SubmitFormButton': 'submitForm',
'click #CloseSupportPanel': 'closePanel'
},
submitForm: function (event) {
alert('form submitted: ' + $('#message'));
}
})
}
Everything is working fine except that "closePanel" gets fired +2 times every time the click event happens. I assume it's some sort of cleanup I'm missing but I don't know what.
Likely its because the event is bubbling up. Try returning false.
I know this is an old question but it helped me realize what my issue was. Returning false as Daniel said works, but the root cause of my issue was having the jQuery selector twice in my markup, resulting in two jQuery objects being created thus the click event fires twice.

Backbone.js:"Maximum call stack size exceeded" error

suppose I have a model and a view ,ths view have two method:one is bind the document mousemove event and the other is unbind method,defalut I give the document mousemove event, once the model's enable value changed I will call the view's unbind method:
window.ConfigModel = Backbone.Model.extend({
defaults: {
'enable':0
},
initialize: function(){
this.bind("change:enable", function () {
var portView2 = new PortView();
portView2.viewOff();
});
},
change:function () {
this.set('enable', 9);
}
})
window.PortView = Backbone.View.extend({
viewOn: function () {
$(document).on('mousemove', function () {
console.log('move')
})
},
viewOff: function () {
$(document).off('mousemove');
}
})
then I put an input on the document to call the model changed:
$('input').click(function () {
var configModel = new ConfigModel();
configModel.change();
})
the boot script is :
var portView1 = new PortView();
portView1.viewOn();
The problem is once I call the click the input button ,the chrome would tell me an error:Maximum call stack size exceeded it seems the change be invoke many times.So what's the problem with my problem ,how can I solve this problem
Backbone models already have a change method:
change model.change()
Manually trigger the "change" event and a "change:attribute" event for each attribute that has changed. If you've been passing {silent: true} to the set function in order to aggregate rapid changes to a model, you'll want to call model.change() when you're all finished.
Presumably something inside Backbone is trying to call configModel.change() and getting your version of change which triggers another change() call inside Backbone which runs your change which ... until the stack blows up.
You should use a different name for your change method.
That said, your code structure is somewhat bizarre. A model listening to events on itself is well and good but a model creating a view is odd:
initialize: function() {
this.bind("change:enable", function () {
var portView2 = new PortView();
portView2.viewOff();
});
}
And instantiating a view simply to call a single method and then throw it away is strange as is creating a new model just to trigger an event.
I think you probably want to have a single ConfigModel instance as part of your application state, say app.config. Then your click handler would talk to that model:
$('input').click(function () {
app.config.enable_level_9(); // or whatever your 'change' gets renamed to
});
Then you'd have some other part of your application (not necessarily a view) that listens for changes to app.config and acts appropriately:
app.viewOn = function() {
$(document).on('mousemove', function() {
console.log('move')
});
};
app.viewOff = function() {
$(document).off('mousemove');
};
app.init = function() {
app.config = new ConfigModel();
app.viewOn();
$('input').click(function () {
app.config.enable_level_9();
});
// ...
};
And then start the application with a single app.init() call:
$(function() {
app.init();
});

Resources