J'aimerais créer un événement personnalisé en JavaScript.
J'ai une application WPF avec un navigateur Web à l'intérieur et une page HTML avec JavaScript.
Je travaille avec une imprimante. Lorsque l'état de l'imprimante change, un événement est généré dans .NET.
Ensuite, j'appelle une méthode JavaScript OnPrinterStateChanged(state)
avec la fonction InvokeScript
du contrôle WebBrowser.
Le problème est que je dois implémenter la méthode OnPrinterStateChanged(state)
dans ma page Web. Je ne peux pas changer le nom de la méthode ou m'abonner/me désabonner à l'événement ...
Je voudrais déplacer la méthode JavaScript OnPrinterStateChanged(state)
dans un fichier JavaScript séparé.
Ce que je veux :
OnPrinterStateChanged(state)
de mon fichier .js séparé, puis l'événement JavaScript est déclenché et la fonction ChangeState
est appelée.J'ai trouvé des solutions mais je n'ai pas réussi à le faire fonctionner ... Quel est le moyen le plus simple de le faire?
Peut-être quelque chose comme ça?
function OnPrinterStateChanged(state) {
var evt = new CustomEvent('printerstatechanged', { detail: state });
window.dispatchEvent(evt);
}
//Listen to your custom event
window.addEventListener('printerstatechanged', function (e) {
console.log('printer state changed', e.detail);
});
Une solution alternative consisterait à utiliser la composition de fonction, mais il serait alors difficile de supprimer des écouteurs spécifiques.
function OnPrinterStateChanged(state) {}
function compose(fn1, fn2) {
return function () {
fn1.apply(this, arguments);
fn2.apply(this, arguments);
};
}
//Add a new listener
OnPrinterStateChanged = compose(OnPrinterStateChanged, function (state) {
console.log('listener 1');
});
//Add another one
OnPrinterStateChanged = compose(OnPrinterStateChanged, function (state) {
console.log('listener 2');
});
MODIFIER:
Voici comment vous pouvez le faire avec jQuery.
function OnPrinterStateChanged(state) {
var evt = $.Event('printerstatechanged');
evt.state = state;
$(window).trigger(evt);
}
//Listen to your custom event
$(window).on('printerstatechanged', function (e) {
console.log('printer state changed', e.state);
});
J'aime utiliser cette méthode de constructeur EventDispatcher
qui, à l'aide d'un élément factice, isole les événements afin qu'ils ne soient déclenchés sur aucun élément DOM existant, ni le window
ou document
. .
J'utilise
CustomEvent
et non pascreateEvent
parce que c'est l'approche la plus récente. Lire la suite ici .
J'aime envelopper chaque méthode native avec ces noms:
on
, off
, trigger
function EventDispatcher(){
// Create a dummy DOM element
var dummy = document.createTextNode('');
// Create custom wrappers with nicer names
this.off = dummy.removeEventListener.bind(dummy);
this.on = dummy.addEventListener.bind(dummy);
this.trigger = function(eventName, data){
if( !eventName ) return;
var e = new CustomEvent(eventName, {"detail":data});
dummy.dispatchEvent(e);
}
}
////////////////////////////////////
// initialize the event dispatcher by creating an instance in an isolated way
var myEventDispatcher = new EventDispatcher();
////////////////////////////////////
// listen to a "foo" event
myEventDispatcher.on('foo', e =>{
console.log(e.type, e.detail);
});
////////////////////////////////////
// trigger a "foo" event with some data
myEventDispatcher.trigger('foo', 123);
EventDispatcher
ci-dessus pourrait être utilisé dans un autre code(par exemple un composant)
function EventDispatcher(){
// Create a dummy DOM element
var dummy = document.createTextNode('');
// Create custom wrappers with nicer names
this.off = dummy.removeEventListener.bind(dummy);
this.on = dummy.addEventListener.bind(dummy);
this.trigger = function(eventName, data){
if( !eventName ) return;
var e = new CustomEvent(eventName, {"detail":data});
dummy.dispatchEvent(e);
}
}
/////////////////////
// Some component: //
/////////////////////
var MyComponent = function(){
// set some default value
this.value = 1;
// merge `EventDispatcher` instance into "this" ('MyComponent' instance)
Object.assign(this, new EventDispatcher());
}
MyComponent.prototype = {
set : function(v){
this.value = v;
this.trigger('change', v);
}
}
var comp = new MyComponent();
// bind a listener to "comp" (which itself is an instance of "MyComponent")
comp.on('change', e =>{
console.log("event type:", e.type, " | event value:", e.detail);
});
// set some value
comp.set(3);
Voir la référence réponse à la question "Espace de noms du gestionnaire d'événements en JavaScript Vanilla"
Condition requise: ES6
let MyClass = (function () {
let __sym = Symbol('MyClass');
class MyClass {
constructor() {
this[__sym] = {};
}
on(event, callback) {
this[__sym][event] = { callback: callback }
}
getError() {
let event = this[__sym].error;
if (event && event.callback) {
event.callback('some parameter');
}
}
}
return MyClass;
}());
let myClass = new MyClass();
myClass.on('error', function (e) {
console.log('error:', e);
});
console.log('before getting error:');
myClass.getError();
Ok j'ai trouvé une solution.
Je devais changer le navigateur Web IE Version pour Internet Explorer 11: http://weblog.west-wind.com/posts/2011/May/21/Web-Browser- Control-Specifying-the-IE-Version
Puis :
function OnPrinterStateChanged(state) {
var evt = document.createEvent("Event");
evt.state = state;
evt.initEvent("printerstatechanged", true, false);
window.dispatchEvent(evt);
}
window.addEventListener('printerstatechanged', function (e) {
// Do something
});