In my init I have set some variables and one animate that uses those variables.
What if I want to use that same animate/variables in my clickSlide?
http://jsfiddle.net/lollero/4WfZa/ ( This obviously wouldn't work. )
I could make it global http://jsfiddle.net/lollero/4WfZa/1/ ( by removing the var )
Question is: Is there a better way, or is this perfectly ok way of doing it?
Put the variable outside the function and than get the value
var getWidth ;
var getHeight ;
$(function(){
var slideBox = {
gb: $('#box'),
init: function() {
sb = this,
getBox = sb.gb,
getWidth = getBox.width(),
getHeight = getBox.height();
getBox.animate({ marginLeft: '+='+getWidth }, 600 );
$("#button").on("click", this.clickSlide);
},
clickSlide: function() {
getBox.animate({ marginLeft: '+='+getWidth }, 600 );
}
};
slideBox.init();
});
than make use in the function so that you can get the vlue in you clickside function
If you are gonna use them a lot, I would made them a property of the object.
Your variables seem unnecessary, you can access everything you need to like this:
http://jsfiddle.net/4WfZa/6/. If you do need to store them you can always add them to the slideBox object and then populate them in init. This way the variables are stored against the object and can be used in any of the functions within it.
For a great article on javascript namespacing, including how to set up private and public variables see this article.
Related
I'd like to 'proxy' (not sure if that's the term at all) a function inside a function object for easy calling.
Given the following code
function Soldier() {
this.el = $("<div></div>").addClass('soldier');
this.pos = this.el.position; // $(".soldier").position(), or so I thought
}
In the console:
s = new Soldier();
$("#gamemap").append(s.el); // Add the soldier to the game field
s.pos === s.el.position // this returns true
s.el.position() // Returns Object {top: 0, left: 0}
s.pos() // Returns 'undefined'
What am I doing wrong in this scenario and is there an easy way to achieve my goal (s.pos() to return the result of s.el.position()) ?
I thought about s.pos = function() { return s.el.position(); } but looks a bit ugly and not apropriate. Also I'd like to add more similar functions and the library will become quite big to even load.
When you're calling s.pos(), its this context is lost.
You can simulate this behavior using call():
s.pos.call(s); // same as s.pos()
s.pos.call(s.el); // same as s.el.position()
This code is actually ok:
s.pos = function() { return s.el.position(); }
An alternative is using bind():
s.pos = s.el.position.bind(el);
You can use the prototype, that way the functions will not be created separately for every object:
Soldier.prototype.pos = function(){ return this.el.position(); }
I'd recommend to use the prototype:
Soldier.prototype.pos = function() { return this.el.position(); };
Not ugly at all, and quite performant actually.
If you want to directly assign it in the constructor, you'll need to notice that the this context of a s.pos() invocation would be wrong. You therefore would need to bind it:
…
this.pos = this.el.position.bind(this.el);
It's because the context of execution for position method has changed. If you bind the method to work inside the element context it will work.
JS Fiddle
function Soldier() {
this.el = $("<div></div>").addClass('soldier');
this.pos = this.el.position.bind(this.el);
}
var s = new Soldier();
$("#gamemap").append(s.el);
console.log(s.pos());
I've been trying to achieve something in javascript and have been unsuccessful. Take a look at the following object
app.Behaviors.pageColor = {
color: 'red',
height: '200px',
width: "200px",
init: function(){
$("div").css({
background: this.color,
height: this.height,
width: this.width
});
}
};
this is just a dummy object, but there are two things i can't get it to do. First, instead of $("div").css(); I'd like to have a variable that is the container the js is invoked on. Second, I'd like the init function to run without calling it... so if the data-behavior attribute is matched and the js is add'ed to my behaviours, it will run the init function. To explain my behaviours talk, this is how all my JS comes together.
// Create the object
var app = window.app || {};
// Create the Behaviors object to store methods
app.Behaviors = {}
// Creates methods of the Behaviors object
app.LoadBehavior = function(context){
if(context === undefined){
context = $(document);
}
context.find("*[data-behavior]").each(function(){
var me = $(this);
var behaviors = me.attr('data-behavior');
$.each(behaviors.split(" "), function(index,behaviorName){
try{
var BehaviorClass = app.Behaviors[behaviorName];
var initalizedBehavior = new BehaviorClass(me);
}
catch(e){
// No Operation
}
}); // each
}); // find
}; // LoadBehavior function
// Call the ready function
$(document).ready(function(){
app.LoadBehavior();
/*** Call this init when the behavior is found, not by declaring it here. ***/
app.Behaviors.pageColor.init();
//Debugging
console.log(app);
});
So this creates a Behaviours object for me to access, based on what data-behavoirs attributes it finds.
Please ask if you have any questions or need more info. Thanks!
Rather than an object, you want to write a function that's called when you create the object as you do when you call var initalizedBehavior = new BehaviorClass(me);. This is Javascript's version of object-oriented programming. It will look like this:
app.Behaviors.pageColor = function(selector) {
// These were your properties:
this.color = 'red',
this.height = '200px';
this.width = "200px";
// This was the `init` property:
$(selector).css({
background: this.color,
height: this.height,
width: this.width
});
}
You can read more about the pattern here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript
Thanks for the comments. I considered the plugin idea (elclanrs) and i read on those mozilla docs (andrew), thanks!
I'll show you what i've come up with. So all i've changed is the document ready in application.js
// Call the ready function
$(document).ready(function(){
// Run the above function
app.LoadBehavior();
// Look for an init function in objects.
$.each(app.Behaviors, function(key, value){
//If
// The Behavoir is an object
// The data-behavior matching the object is found in the dom
// The object has an init function
if($.type(value) === 'object' && $("*[data-behavior="+key+"]").length && jQuery.isFunction(value.init) ){
return value.init(key);
}
}); //each
});
So this find's any objects in the behaviors object and i'm testing because you can do it like andrew said and use a function which will run when called anyways. Then it looks for an init function and run's it.
This way, I can use literal notation objects (which i like personally / was my goal here).
Question: Does anything look weird about my if statement inside the each? I can't think of any pitfalls with this but i would love for any critique. my app.js and object.js have stayed the same.
Every time I need a static variable, I end up tacking it on as a property to the object that uses it and needs it to persist.
Particularly, this index here(MT.MAOrb.startR.index) I need to be static or hold it's value until the function is called again by a callback.
Is using this form the best way to do this?
MT.MAOrb.startR.index
/**
** MAOrb
*/
MT.MAOrb =
{
pre : function() {
var o_p = {
model : 'MAOrb'
};
return o_p;
},
post : function( o_p ) {
MT.MAOrb.startR( o_p );
},
startR: function( o_p ){
var sky = document.getElementById( 'Ab1' );
if( MT.MAOrb.startR.index === undefined ) {
var size = Object.size( o_p );
console.log( 'size' + size );
var index1 = MT.MAOrb.random( 0, size - 1 );
console.log( 'index1' + index1 );
MT.MAOrb.startR.index = index1;
MT.MAOrb.startR.o_p = o_p;
}else{
MT.MAOrb.startR.index++;
}
var image_element = MT.MAOrb.makeElement( MT.MAOrb.startR.o_p[ MT.MAOrb.startR.index ] );
sky.appendChild( image_element );
MT.MAOrb.moveLinear( image_element );
},// ....more code here
};
If you are trying to emulate a public static property, then that's a totally A-OK way to do it.
JavaScript is not a classical object oriented language. It is prototypical.
One ramification is that there really isn't a concept of static in the language.
The way you're doing it is totally fine, as long as you don't mind that another object can directly read and modify the property.
Javascript has no concept of static vs. non-static variables: everything is just a property of an object. As such, there is no right or wrong way of doing static variables, only right or wrong ways of doing static-like variables.
That being said, adding the variable as a property of a fixed (module-like) object, as you're doing, is pretty much your best bet (ie. best practice). Unless you're using a library like Backbone.js that is, which actually does add support for static variables to its "models" (ie. it's class system).
I'd say that it's actually a rather strange way to do it. Javascript provides function level scope, and you can use that to your advantage by using an immediately-invoked-function-expression (IIFE):
myObject = {
count: (function () { // this function is invoked immediately
var staticCounter = 0;
return function () { // this is the actual 'count' function
return ++staticCounter;
};
}())
};
myObject.count(); // 1
myObject.count(); // 2
One reason that this could be considered a better approach is that it completely hides the static variable. If you were to do myObject.count.staticCounter, some other code might be reading or writing to that variable. Obviously you wouldn't want that to happen, but if you do this, you are completely guaranteed of that variable's scope, which leads to easier debugging and refactoring in the future.
I don't think I'm the first one to run into this issue but I haven't find a way to search for this without getting results that have nothing to do with the issue.
I adopted the not so extended good practice of "caching" repetitive jQuery selections into vars like var element = $('#element'); to prevent "DOM pool searching" for every repeated use of the element
The problem I'm having is that now I'm doing this caching inside a function. Something like:
function functionname (id) {
var id = $('#'+id);
//extra stuff
}
I'm not expert in variables scopes but I'm not being able to do
functionname ('some-div-id');
some-div-id.dialog('open');
So I'm pretty sure it's because the variable created inside the function is not accesible outside the function itself.
Then I came up with
function functionname (id) {
window.id = $('#'+id);
//extra stuff
}
but if I try to do window.some-div-id.dialog('open'); I get TypeError: 'undefined' is not a function
What am I missing? I'm sure it's a small dumb thing but I'm missing it just in front of my eyes.
Thanks
EDIT
Thanks everyone but you're missing something.
The code suggestions are missing the fact that the inside "global" variable name is dynamic:
var CACHEobject = {};
function doSomething (NAMEHERE) { //note the function parameter
CACHEobject.NAMEHERE = $('#'+NAMEHERE);
}
So the idea is that the function creates a javascript variable with the same name that the #element_id. If I pass a name to the function it should select the html id with that name and "cache it" to a global variable with the same name:
doSomething('myDialogOne'); doSomething('myDialogTwo');
so I can later do
CACHEobject.myDialogOne.dialog('open'); CACHEobject.myBox.dialog('close');
This is what you want (based off the edit):
var CACHEobject = {};
function doSomething(id) {
CACHEobject[id] = $('#' + id);
}
Your idea is fine. Just set up an object for that. Here's an example using STASH as the caching object:
<html>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>
var STASH = {};
$(document).ready(function(){
// stash your elements
STASH.item = $('#item');
STASH.otherItem = $('#otherItem');
// do stuff to them
STASH.item.css({
color: '#f00'
}); // sets #item to red
alert(STASH.otherItem.text()); // alerts foo
});
</script>
<style></style>
<body>
<div id="item">bar</div>
<div id="otherItem">foo</div>
</body>
</html>
window.some-div-id.dialog('open');
is interpreted as:
window.some - div - id.dialog('open');
i.e. subtracting, which causes three undefined variables, one of which is id.dialog which causes an error when trying to be executed as a function.
For special characters, use:
window["some-div-id"].dialog('open');
And to define:
window[id] = $("#" + id);
Anyhow, I would not advise you to use global variables. You'd better overwrite the jQuery function to implement caching (using an object with the selector as key and the matched element as value).
You could just declare the variable outside the function.
var $foo;
function some_function(id) {
$foo = $('#' + id);
}
function setDialog(selector) {
window.$dialogElem = $(selector);
//window.dialogSelector = selector;
}
var id= 'mensajes';
setDialog('#'+id);
window.$dialogElem.dialog();
//$(window.dialogSelector).dialog();
commented stuff is an alternative that takes less memory. But why the hell use window?? check this fiddle for various simple techniques.
I'm trying to create a simple, small and basic javascript framework just for learning purposes.
But the thing is that i'm allready stuck at the very basics.
I'm trying to do something like this:
$('testdiv').testFunction();
And the code i've written for that:
var elementID;
var smallFramework = {
$:function(id) {
this.elementID = id;
},
testFunction:function() {
alert(this.elementID);
}
};
window.$ = smallFramework.$;
But in return I get:
$('testdiv) is undefined
Can anyone help me with this small and hopefully easy question?
To get the behavior you're expecting, you need the $ function to return an object with a method named testFunction.
Try:
var smallFramework = // an object for namespacing
{
$:function(id) // the core function - returns an object wrapping the id
{
return { // return an object literal
elementID: id, // holding the id passed in
testFunction: function() // and a simple method
{
alert(this.elementID);
}
};
}
};
Of course, there are many other ways to achieve the behavior you desire.
If you're trying to add methods to an HTML element you could do something along these lines.
$ = function( elementId ) {
var element = document.getElementById( elementId );
element.testFunction = function(){
alert( this.id );
return this; // for chaining
}
return element;
}
$('test').testFunction();
Try
smallFramework.$('testdiv');
instead. According to the code you posted, that's where your $ function ended up.
Or alternatively, it looks like you're trying to replicate something like jQuery. You might want to try something like this.
var $ = smallFramework = (function () {
var f =
{
find:function(id) {
f.elementID = id;
return f; //every function should return f, for chaining to work
},
testFunction:function() {
alert(f.elementID);
return f;
}
}
return f.find //the find function will be assigned to $.
//and also assigned to smallFramework.
//the find function returns f, so you get access to testFunction via chaining
// like $("blah").testFunction()
})() //note this function gets called immediately.
this code may look confusing to someone new to JavaScript because it depends heavily on the concept of closures. I suggest that if this doesn't make sense, spend some time at Douglas Crockford's JavaScript website. This is important because the code above will bite if you happen to use this in the find function because this won't be bound to f, as you may expect it to be when you use it from $ or smallFramework.