Reputation: 253446
Given the following JavaScript (the relevant HTML will be posted at the bottom of the question):
var app = {
// other objects from 'messages' array removed for brevity
'messages': [{
'author': 'Maya Angelou',
'quote': "If you don't like something, change it. If you can't change it, change your attitude."
}],
'textProp': 'textContent' in document.body ? 'textContent' : 'innerText',
'outputTo': document.querySelector('#output'),
'trigger': document.querySelector('#load'),
'quote': function () {
var n = Math.floor(Math.random() * this.messages.length),
f = document.createElement('figure'),
c = document.createElement('figcaption'),
frag = document.createDocumentFragment();
f[this.textProp] = this.messages[n].quote;
c[this.textProp] = this.messages[n].author;
frag.appendChild(f);
frag.appendChild(c);
this.outputTo.innerHTML = '';
this.outputTo.appendChild(frag);
}
};
We can call the quote()
function from outside of the object using the following:
document.getElementById('load').addEventListener('click', app.quote.bind(app));
Or by simply calling the function directly (not bound as a callback to an event-handler):
app.quote();
However, I tried to create an event-handler within the object itself, using:
'clickhandler': function(){
this.trigger.addEventListener('click', this.quote);
}
This, of course, failed (as expected, since this
here is (using an IIFE) this Window
object).
I realise that this
will, while the object is being created/prior to its initialisation, refer to the Window
object, but is there a way I'm not seeing to create, and trigger, the event-handling within the object itself?
I realise that a large portion of my imaginary internet points comes specifically from JavaScript, but learning it accidentally leads to moments of utter confusion and inadequacy; this is not to excuse my ignorance but to explain it.
Finally, the HTML (such as it is):
<button id="load">Switch message</button>
<div id="output"></div>
Incidentally, I've looked at the following linked/suggested questions:
For clarity, I'm trying to create the object itself and have the event-handling created and assigned entirely within/'by' the object, without having to call its methods afterwards. That's the part where I'm stuck (and which I suspect may be impossible).
app
object following its initialisation by adding a new method, which is do-able, but does rather go against what I want to do (and I realise that life is not fair, but even so...).Upvotes: 3
Views: 92
Reputation: 4744
A small change. Declaring the Object before initializing its properties might help your usecase.
var app = {};
app["messages"] = "test message";
app["textProp'] = 'textContent' in document.body ? 'textContent' : 'innerText';
app['quote']= function () {
var n = Math.floor(Math.random() * this.messages.length),
f = document.createElement('figure'),
c = document.createElement('figcaption'),
frag = document.createDocumentFragment();
f[app.textProp] = app.messages[n].quote;
}
Upvotes: 0
Reputation: 160923
Instead of object literal, you could do the below:
var app = new function () {
this.messages = [{
'author': 'Maya Angelou',
'quote': "If you don't like something, change it. If you can't change it, change your attitude."
}, {
'author': 'Richard Feynman',
'quote': "Hell, if I could explain it to the average person, it wouldn't have been worth the Nobel prize."
}, {
'author': 'Eddie Izzard',
'quote': "Cats have a scam going – you buy the food, they eat the food, they fuck off; that's the deal."
}, {
'author': 'George Carlin',
'quote': "I would never want to be a member of a group whose symbol was a man nailed to two pieces of wood. Especially if it's me!"
}];
this.textProp = 'textContent' in document.body ? 'textContent' : 'innerText';
this.outputTo = document.querySelector('#output');
this.trigger = document.querySelector('#load');
this.quote = function () {
var n = Math.floor(Math.random() * this.messages.length),
f = document.createElement('figure'),
c = document.createElement('figcaption'),
frag = document.createDocumentFragment();
f[this.textProp] = this.messages[n].quote;
c[this.textProp] = this.messages[n].author;
frag.appendChild(f);
frag.appendChild(c);
this.outputTo.innerHTML = '';
this.outputTo.appendChild(frag);
};
this.trigger.addEventListener('click', this.quote.bind(this));
};
Upvotes: 1
Reputation: 665130
At some point, you will need to .bind()
the method to your app
(unless you avoid the use of this
and replace it with app
everywhere). This is however not necessarily in the place where you pass the app.quote
method (e.g. bind as the event listener), but might be directly after the declaration of the app
object:
var app = {
…,
quote: function() {
… this …
}
};
app.quote = app.quote.bind(app);
If you have Underscore around, you might use the bindAll
helper function for this:
var app = _.bindAll({
…,
quote: function() {
… this …
}
}, "quote");
If you are not in an object literal - it could be a constructor, IEFE, whatever - you can .bind()
the function directly at the place of its declaration:
function App() {
…
this.quote = function() {
… this …
}.bind(this);
}
With coffeescript or ES6, you can also use the fat-arrow function syntax as a sugar for this.
Upvotes: 1
Reputation: 2832
The this variable is just referencing app. So just use app.
var app = {
someVar: 'thing',
someMethod: function(){
alert(app.someVar);
}
};
or you can do
function createApp(){
var app = {};
app.someVar = 'thing';
app.someMethod = function(){
alert(app.someVar);
};
return app;
}
Upvotes: 0
Reputation: 13649
As you specified if you just want to create a new object you probably need to go this way. I think what ever you do you still need to execute something - be it instantiate an object or run a specific init function that binds the click.
var App = function App(){
this.clickhandler()
}
App.prototype =
{
'messages': [{
'author': 'Maya Angelou',
'quote': "If you don't like something, change it. If you can't change it, change your attitude."
}, {
'author': 'Richard Feynman',
'quote': "Hell, if I could explain it to the average person, it wouldn't have been worth the Nobel prize."
}, {
'author': 'Eddie Izzard',
'quote': "Cats have a scam going – you buy the food, they eat the food, they fuck off; that's the deal."
}, {
'author': 'George Carlin',
'quote': "I would never want to be a member of a group whose symbol was a man nailed to two pieces of wood. Especially if it's me!"
}],
'textProp': 'textContent' in document.body ? 'textContent' : 'innerText',
'outputTo': document.querySelector('#output'),
'trigger': document.querySelector('#load'),
'quote': function () {
console.log('hey')
var n = Math.floor(Math.random() * this.messages.length),
f = document.createElement('figure'),
c = document.createElement('figcaption'),
frag = document.createDocumentFragment();
f[this.textProp] = this.messages[n].quote;
c[this.textProp] = this.messages[n].author;
frag.appendChild(f);
frag.appendChild(c);
this.outputTo.innerHTML = '';
this.outputTo.appendChild(frag);
},
'clickhandler' : function(){
this.trigger.addEventListener('click', this.quote.bind(this));
}
};
//just create an object
app = new App();
Upvotes: 1