2 votes

Impossible d'accéder à ceci dans un événement de clic en JavaScript

Ci-dessous, j'ai un simple dialogue modal script sur lequel je travaille. Il utilise Bootstrap Modal pour le côté CSS de la chose.

Mon objectif était de créer une simple boîte de dialogue modale qui s'affiche et requiert une action de la part de l'utilisateur (clic sur le bouton ok ou annuler). Je voulais le rendre flexible pour une utilisation dans de futurs projets en permettant à certaines fonctions de rappel d'être passées et appelées lorsque ces événements de clic ont lieu. Il y a aussi d'autres options comme afficher ou non le bouton d'annulation. (Je n'ai pas encore ajouté cette partie).

Ce que je fais donc, c'est que la fonction accepte un objet d'options/de paramètres. J'ai également des options/réglages par défaut dans lesquels les options de l'utilisateur se fondent, ce qui permet aux options de l'utilisateur d'être facultatives et de remplacer les options par défaut si elles sont présentes.

Je sais qu'il existe plusieurs façons de procéder, mais c'est la méthode que j'ai vue dans quelques projets étudiés par des développeurs JS que je respecte.

Voici donc mon code JavaScript, une page JSFiddle avec le code, et une page JSFiddle Output pour voir le résultat.

Dans le code, à mi-chemin, il y a un commentaire // PROBLEM AREA DOES NOT CALL THE CALLBACK FUNCTION

Dans ce domaine, j'ai essayé 3 choses différentes jusqu'à présent...

this.options.cancelCallback(); // This is what I wanted to work!
zPanel.dialog.confirm.options.cancelCallback(); Tried this 2nd
options.cancelCallback(); // This Works if there is a user defined callback but errors when not

Donc mon problème dans ce domaine en ce moment est que lorsque j'appelle this.options.cancelCallback() dont DEVRAIT contient la fonction de rappel, si l'utilisateur en a passé une, elle devrait être réaffectée à cette propriété, si l'utilisateur ne l'a pas fait, il devrait au moins voir une propriété vide par défaut.

Je pense que le this La partie est malencontreuse car elle se trouve à l'intérieur de la fonction onclick qui, d'ailleurs, ne ressemble pas à un événement de clic normal, je l'ai vu dans un autre projet et cela "fonctionnait".

Le message d'erreur que je reçois est donc Uncaught TypeError: Cannot call method 'okCallback' of undefined

Quelqu'un peut-il me montrer comment contourner ce problème ou l'améliorer ? Merci.

JSFiddle http://jsfiddle.net/jasondavis/dymn5/

Aperçu plein écran http://jsfiddle.net/jasondavis/dymn5/show/result/

var zPanel = {

    dialog: {

        confirm: function (options) {

            var i;

            // Default options
            this.options = {
                message: "",                    // String: Default Message
                cancelButton: true,             // Boolean: Show Cancel Button
                okButton: true,                 // Boolean: Show Ok Button
                cancelCallback: function () {}, // Function: Callback function when Cancel button clicked
                okCallback: function () {}      // Function: Callback function when Ok button clicked
            };
            // Merge User defined options
            for(i in options) {
                if(i in this.options) {
                    this.options[i] = options[i];
                } else {
                    throw new Error("Notice doesn't support option: " + i);
                }
            }

            var container = document.createElement('div');
            //template for modal window
            container.innerHTML += '<div class="modal-content confirm">' +
                '<div class="modal-body">' +
                '<div>' + this.options.message + '</div>' +
                '<div class="controls">' +
                '<button type="button" class="btn primary">OK</button>' +
                '<button type="button" class="btn">Cancel</button>' +
                '</div>' +
                '</div>' +
                '</div>';

            //modal window
            var modal = container.firstChild;
            container = document.createElement('div');
            container.innerHTML = '<div class="modal-backdrop fade in"></div>';
            //dark background
            var background = container.firstChild;

            //Find OK button
            var ok = modal.getElementsByTagName('button')[0];
            ok.onclick = function () {
                modal.parentNode.removeChild(modal);
                document.body.removeChild(background);

                // PROBLEM AREA DOES NOT CALL THE CALLBACK FUNCTION
                this.options.okCallback();
                //zPanel.dialog.confirm.options.okCallback();
                //options.okCallback(); // Works if there is a user defined callback
            }

            //Find Cancel button
            var cancel = modal.getElementsByTagName('button')[1];
            cancel.onclick = function () {
                modal.parentNode.removeChild(modal);
                document.body.removeChild(background);

                // PROBLEM AREA DOES NOT CALL THE CALLBACK FUNCTION
                this.options.cancelCallback();
                //zPanel.dialog.confirm.options.cancelCallback();
                //options.cancelCallback(); // Works if there is a user defined callback
            }

            document.body.appendChild(background);
            document.body.appendChild(modal);
        }

    }

}

// Create a Dialog on Click event
$('#delete_btn').click(function () {
    zPanel.dialog.confirm({
        message: 'Are you sure you want to delete action?',
        cancelCallback: function(){alert('user pressed Cancel button')},
        okCallback: function () {alert('id deleted')},
    });
});

6voto

Ian Points 23712

Le contexte de this les changements à l'intérieur d'une fonction, notamment les gestionnaires d'événements. C'est également un problème courant lorsque l'on utilise setTimeout .

this fera référence à l'élément dans lequel l'événement s'est produit. Une manière de surmonter ce problème est de stocker la valeur de this en dehors du gestionnaire dans une nouvelle variable de la fonction conteneur, puis de faire référence à cette variable dans le gestionnaire.

Ajoutez donc quelque chose comme ceci dans votre confirm méthode :

var self = this;

Et dans vos manipulateurs, utilisez :

self.options.cancelCallback();

DEMO : http://jsfiddle.net/dymn5/3/

Et pour fournir au callback passé le contexte du handler, vous pouvez utiliser ceci :

self.options.cancelCallback.apply(this, arguments);

De sorte que le cancelCallback de la valeur de this sera l'élément dans lequel l'événement se produit, et recevra tous les arguments qui lui seront passés, comme la fonction event objet.

Cela vous permet de l'utiliser pour vos options :

.confirm({
    cancelCallback: function (e) {
        // `this` refers to the button
        // `e` refers to the event
    }
});

1voto

Bart Points 2015

En javascript, this fait toujours référence au "propriétaire" d'une fonction.

// example 1: function without an owner
var displayA = function() { console.log(this.a); }
displayA(); // undefined

// example 2: object with a function member
var obj = {
    a: 1,
    displayA: displayA
}

obj.displayA(); // logs "1"
// note that obj.displayA is the exact same function as displayA. But when it is called, obj is the owner of the function.

Dans le premier exemple, displayA n'a pas de "propriétaire". Quand une fonction n'a pas de propriétaire, this est automatiquement considéré comme l'objet global ( window dans les navigateurs).

Dans le deuxième exemple, le propriétaire de displayA es obj . Dans ce cas, this se référera à obj et donc obj.a (c'est-à-dire la valeur 1) s'affiche.

Les méthodes courantes pour résoudre ce problème sont les suivantes :

// storing `this` in a variable, when a callback function needs a reference to this
var self = this;
window.onload = function() { 
    // I can use self instead of this!
    self.doStuff();
}

// using Function#call or Function#apply
// let's say I want to use the "obj" variable as the "this" reference in a function:
function myFunction(a, b) { this.doStuff(a, b); }
myFunction.call(obj, a, b); // after obj, pass normal function arguments
myFunction.apply(obj, [a, b]); // after obj, pass function arguments in an array

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X