I'm using require.js and have a library of functions I use in multiple places. I define the functions thusly:
define(function (require) {
"use strict";
var $ = require('jquery');
var UsefulFuncs = {};
UsefulFuncs.hideAlert = function() {
$('.alert').hide();
};
UsefulFuncs.loadURL = function (url){
navigator.app.loadUrl(url, { openExternal:true });
return false;
};
UsefulFuncs.linkClicked = function (e) {
e.preventDefault();
var url = $(e.currentTarget).attr("rel");
this.loadURL(url);
};
return UsefulFuncs;
});
Then, in my backbone view, I call a function from the library with:
UsefulFuncs = require('app/utils/useful_func'),
....
UsefulFuncs.linkClicked
This works fine for any standalone function in the library e.g. hideAlert(). However when one function in the library refers to another, such as linkClicked() calling loadURL(), I get an error:
Uncaught TypeError: Object [object Object] has no method 'loadURL'.
Any ideas how I can reference loadUrl()?
I would assume you set UsefulFuncs.linkClicked as a handler for an event.
If you were to use it like this:
UsefulFuncs.linkClicked()
, this inside the function would refer to UsefulFuncs, so this.loadURL() would be valid.
However, since you set it as a handler for an event, it can be called in other ways, and this is set to some other object (probably the element which triggered the event). To avoid the event handling mechanism changing your this, you can bind the function when you assign it:
element.onclick = UsefulFuncs.linkClicked.bind(UsefulFuncs);
Another way to go around it is to avoid using this in the handler, like so:
UsefulFuncs.linkClicked = function (e) {
e.preventDefault();
var url = $(e.currentTarget).attr("rel");
UsefulFuncs.loadURL(url);
};
This creates a closure over UsefulFuncs (the first method does as well, but it's more standardized).
Try something like this:
define(function (require) {
"use strict";
var $ = require('jquery');
var hideAlert = function() {
$('.alert').hide();
};
var loadURL = function (url){
navigator.app.loadUrl(url, { openExternal:true });
return false;
};
var linkClicked = function (e) {
e.preventDefault();
var url = $(e.currentTarget).attr("rel");
loadURL(url);
};
return {
hideAlert : hideAlert,
loadURL : loadURL,
linkClicked : linkClicked
};
});
Related
I'm only learning how to work with the modules in JavaScript, so I have three separate .js files: main, listener and fileHandler
Simply this is a program that for every selected or dropped file(image) from computer gets appended to the page. Functions are working when I drag and drop files to the page, but when I select them through inputBox button files even files are stored in inputBox.files, they are not getting appended to the page.
var uploader = {};
uploader.init = function () {
this.inputBox = document.getElementById('uploadButton');
this.dropbox = document.getElementById('dropbox');
this.listener();
}
and listener method as:
probably I'm calling 'change' event wrongly here, that files are not appended.
uploader.listener = function () {
uploader.inputBox.addEventListener('change', uploader.fileHandler.addFiles(uploader.inputBox.files));
this.dropbox.addEventListener('drop', this.fileHandler.drop.bind(this));
}
one another constructor is:
uploader.fileHandler = new function () {
var uploadHandler = function () {...}
this.addFiles = function (files) {
Object.keys(files).forEach(function (key) {
var file = files[key];
uploadHandler(files[key]);
});
};
this.drop = function (event) {
event.stopPropagation();
event.preventDefault();
var files = event.dataTransfer.files;
this.fileHandler.addFiles(files);
};
}
EDIT
I see another issue. When you do this:
uploader.inputBox.addEventListener('change', uploader.fileHandler.addFiles(uploader.inputBox.files));
You are calling uploader.fileHandler.addFiles(uploader.inputBox.files) immediately and passing it's return value to .addEventListener(). Probably what you want instead is this:
uploader.inputBox.addEventListener('change', function() {
uploader.fileHandler.addFiles(uploader.inputBox.files)
});
Here you are passing an anonymous function reference which can be called later by the event handler.
This construct:
uploader.fileHandler = new function () {
this.addFiles = function (files) {
Object.keys(files).forEach(function (key) {
var file = files[key];
uploadHandler(files[key]);
});
};
}
only assigns a function to uploader.fileHandler. It does not define uploader.fileHandler.addFiles until you actually call that function (which you do not show).
I don't know why you're trying to nest your function definitions (that usually just causes more complexity than benefit in Javascript), but if you really wanted to define them that way, you could do this:
uploader.fileHandler = {
addFiles: function (files) {
Object.keys(files).forEach(function (key) {
var file = files[key];
uploadHandler(files[key]);
});
},
drop: function(...) {...}
};
This would then define both of these functions:
uploader.fileHandler.addFiles()
uploader.fileHandler.drop()
All:
What I want to do is like:
On Node server side:
var fn = function(){
alert("hello");
}
I want to send this function to client side(currently using AngularJS, but it does not matter as long as this problem can be solved), and bind it to a button click event. So I can get pop-out alert window when click that button.
Thanks
So, something like this:
// Predefined functions
var allowedFunctions = {
'f1': function () {alert('Called f1');},
'f2': function () {alert('Called f2');},
'f3': function () {alert('Called f3');},
};
// This comes from the server
var callThisOne = 'f2';
// Here's how you call it now
allowedFunctions[callThisOne]();
Here's a plunk.
// Get this from the server
var textReceived = 'var fn = function(){ alert("hello"); };';
function getFunction(textReceived) {
eval(textReceived);
return fn;
}
var f = getFunction(textReceived);
f();
var fbToggle = document.getElementById("fbToggle");
and later in the script
fbToggle.addEventListener("click", toggle("fbContainer"));
Console tells me that fbToggle is NULL
This is in the document though.
<input type="checkbox" id="fbToggle">
I wasnt using eventListener before, so maybe there is a special order of declaration i'm missing ?
EDIT :
entire js :
function toggle(target) {
var obj = document.getElementById(target);
display = obj.style.display;
if (display == "none") {display = "block"}
else {display = "none"}
}
function init() {
var fbToggle = document.getElementById("fbToggle");
var twitToggle = document.getElementById("twitToggle");
var pinToggle = document.getElementById("pinToggle");
console.log(fbToggle); // NULL
fbToggle.addEventListener("click", toggle("fbContainer"));
twitToggle.addEventListener("click", toggle("twitContainer"));
pinToggle.addEventListener("click", toggle("pinContainer"));
}
window.onload = init();
HTML is way too long.but JS is in head, called from external file. Also i'm not in quirk mode.
It is not clear where "later in the script" is. If it is in different scope definitely it is not going to work. Suggesting you to keep everything in a global object if possible so that you can access from different places in the script.
window.globals = {};
window.globals.fbToggle = document.getElementById("fbToggle");
window.globals.fbToggle.addEventListener("click", function () {
toggle("fbContainer")
});
function toggle(container) {
alert(container);
}
http://jsfiddle.net/ST938/
Another point is addEventListener expects a function or function idenitifier, NOT a function call.
addEventListener("click", toggle("fbContainer")); // wrong
addEventListener("click", toggle); // correct
So if you want to pass a parameter
window.globals.fbToggle.addEventListener("click", function () {
toggle("fbContainer")
});
function toggle(container) {
alert(container);
}
In JavaScript, putting brackets after a function name causes it to be called. If you want to reference a function without calling it you must not put brackets after the name:
window.onload = init(); // this calls init() immediately
window.onload = init; // this correctly stores init in window.onload
The same applies to toggle(). If you need to pre-specify some of the arguments you can wrap it in an anonymous function:
fbToggle.addEventListener("click", function() { toggle("fbContainer"); });
or you can use bind:
fbToggle.addEventListener("click", toggle.bind(null, "fbContainer"));
I got my view like this :
render:function(){
this.template = _.template(tpl.get('tplUsersManagement'));
this.$el.html(this.template({models : this.model.models}));
this.$el.i18n();
$('#formAddUser')
.on('invalid', function () {
var invalid_fields = $(this).find('[data-invalid]');
console.log(invalid_fields);
})
.on('valid', this.addUser);
return this;
},
addUser: function(event){
event.preventDefault();
var newUser = new UserModel({
. . .
});
var that=this;
newUser.save({},{
headers:{"X-Token":"theToken"},
statusCode:{
202: function(){
that.render();//here I want to call render function
}
}});
}
}
So I want to call my render function from my addUser function. I try to do it with this=that and then that.render but I got an error and it says that :
Uncaught TypeError: Object # has no method 'render'
I think its because in the event handler this become my form.
You are already aware of the context constraints and that's why you are using the var that = this trick, but there is another place you need to implement it:
var self = this; // I prefer "self" rather than "that"
$('#formAddUser').on('invalid', function () {
// handle invalid data
}).on('valid', function( ev ){
ev.preventDefault();
self.addUser();
return this;
});
The addUser function is part of your view module, but within the valid/invalid event handlers, the context (the this variable) is changed. You'll need to keep a reference of the correct context (var self = this;) before entering the scope of the event handler so that it can be used to call your addUser() function.
There will be 2 options.
1.Use event delegation of backbone view. It will be let you use your view object in event handler.
2.Bind your addUser function to this.
addUser: function() {
...
//do something
...
}.bind(this)
How can I do that?
It seems that you can have multiple jQuery's ready() functions, and they will all run when the DOM is loaded.
So how can I create my own ready()-like function? :)
function _addEvent(e, evt, handler){
if(evt == "ready")
evt = "DOMContentLoaded";
if(typeof handler !== 'function')return;
if (e.addEventListener)
e.addEventListener(evt, handler, false);
else if (e.attachEvent)
e.attachEvent("on" + evt, handler);
else
{
var oldHandler = e["on" + evt];
function newHandler(event){
handler.call(e, event);
if(typeof oldhandler === 'function')oldhandler.call(e, event);
}
}
}
var _events = ["ready", "click", "mousedown"]; //...
var _myLib = function(item){
function eventWorker(item, event){
this.add = function(handler){
_addEvent(item, event, handler);
};
}
for(var i=0;i<_events.length;i++)
this[_events[i]] = (new eventWorker(item, _events[i])).add;
};
var MyLib = function(item){
return new _myLib(item);
};
MyLib(document).ready(function(){alert("I am ready!");});
Test =>
http://jsfiddle.net/vgraN/
First, you need to identify what it is you need the function for - is it to respond to a particular browser event?
jQuery's $(document).ready(fn) uses an array internally to hold the functions to execute when the DOM has loaded. Adding a new ready(fn) call appends the function fn to the array. When the DOM has loaded (which is detected in various ways according to which browser the code is executing within), each function in turn in the array is executed. Any functions added using ready(fn) after the DOM has loaded are executed immediately.
In summary, you can use an array to store the functions to execute whenever it is that you need to execute them.
Take a look at domready, a standalone port of the ready(fn) function from jQuery to get some ideas about how to go about it.
It sounds like you want to make an array of functions and append new callbacks to it.
It's not easy to do cross browser.
If you assume the DOMContentLoaded event exists then you can just make
var domready = (function () {
var cbs = [];
document.addEventListener("DOMContentLoaded", function () {
cbs.forEach(function (f) {
f();
});
});
return function (cb) {
cbs.push(cb);
};
})();
You can use other fallbacks like window.onload and a hackish scroll check like jQuery does.
I'd recommend either using domready or reading the source.
Do you want to create a function which when passed a function will call that function at a particular time? (Also, it can be called multiple times.) If so this is how I would do it it. (Based on jQuery code.)
var funcQueue = (function () {
var funcList = [];
function runAll() {
var len = funcList.length,
index = 0;
for (; index < len; index++)
funcList[index].call(); // you can pass in a "this" parameter here.
}
function add(inFunc) {
funcList.push(inFunc);
}
})();
To use:
funcQueue.add(function () { alert("one"); });
funcQueue.add(function () { alert("two"); });
funcQueue.runAll(); // should alert twice.