Reputation: 5405
I'm trying to transform my code into a more plugin type of code, so everything will be separated, in case I change class names in the future.
For some reason, in my code, I get Cannot read property 'dropdown' of undefined
.
My guess is, the function Navigation.bindEvents()
runs before I set the config, so It can't find it... But I don't know how to solve it.
Here's my Navigation.js file:
let Navigation = {
config: {},
init(config) {
this.config = config;
this.bindEvents();
},
bindEvents() {
$(this.config.trigger).on('click', this.toggleNavigation);
$(document).on('click', this.hideAllDropdowns);
},
toggleNavigation(event) {
// Store the current visible state
var visible = $(this).siblings(this.config.trigger).hasClass('visible');
// Hide all the drop downs
this.hideAllDropdowns();
// If the stored state is visible, hide it... Vice-versa.
$(this).siblings(this.config.content).toggleClass('visible', !visible);
event.preventDefault();
event.stopPropagation();
},
hideAllDropdowns() {
$(this.config.dropdown + ' ' + this.config.content).removeClass('visible');
}
}
export default Navigation;
And here's my app.js file which I run all the init
functions.
window.$ = window.jQuery = require('jquery');
import Navigation from './layout/navigation.js';
Navigation.init({
dropdown: '.dropdown',
trigger: '.dropdown-trigger',
content: '.dropdown-content'
});
Upvotes: 0
Views: 2389
Reputation: 8497
The behavior of this
is one of the hardest things to understand in JavaScript. Here this
is obviously dynamic, which means that its value depends on where your method has been called...
let module = {
config() {
console.log(`config(): 'this' is 'module' ---> ${Object.is(this, module)}`);
console.log(`config(): 'this' is 'document' ---> ${Object.is(this, document)}`);
},
init() {
console.log(`init(): 'this' is 'module' ---> ${Object.is(this, module)}`);
console.log(`init(): 'this' is 'document' ---> ${Object.is(this, document)}`);
module.config();
}
};
$(document).ready(module.init);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Upvotes: 1
Reputation: 2776
I guess you got problem with the scope $(document).on('click', this.hideAllDropdowns);
Let's try
bindEvents() {
$(this.config.trigger).on('click', this.toggleNavigation);
$(document).on('click', this.hideAllDropdowns.bind(this));
},
UPDATE:
bindEvents() {
$(this.config.trigger).bind('click', {self:this}, this.toggleNavigation);
$(document).on('click', this.hideAllDropdowns.bind(this));
},
And replace all this.config
by event.data.self
inside toggleNavigation
function
Upvotes: 2
Reputation: 555
this
in the context of toggleNavigation
refers to the clicked element.
That is why you can do $(this).siblings(...)
to get the sibling elements.
You need to have a reference to the Navigation object. Perhaps you can use the on
syntax that allows you to pass extra data $(this.config.trigger).on('click', this, this.toggleNavigation);
Then rewrite the handler
toggleNavigation(event) {
//get the navigation reference
var nav = event.data;
// Store the current visible state
var visible = $(this).siblings(nav.config.trigger).hasClass('visible');
// Hide all the drop downs
nav.hideAllDropdowns();
// If the stored state is visible, hide it... Vice-versa.
$(this).siblings(nav.config.content).toggleClass('visible', !visible);
event.preventDefault();
event.stopPropagation();
},
Upvotes: 1