So, I have this constructor set up with some prototypes methods and because I need the behavior (that this object creates ) to apply to a few diff. elements, I was wondering if there is a better way than doing the following.
var MAINFUNC = function(opts){
this.options = {
item1 : 'somevalue'
},
this.init(opts);
}
MAINFUNC.prototype = {
someFunc1: function(){
// do stuff
},
someFunc2: function(){
// do stuff
},
someFunc3: function(){
// do stuff
},
init: function(data){
$.extend(this.options, data);
this.someFunc1();
}
};
var obj1Create = new MAINFUNC({ someoptions });
var obj2Create = new MAINFUNC({ someoptions });
var obj2Create = new MAINFUNC({ someoptions });
So, its the last three obj instantiations that seem a tad bit obtuse. Perhaps I am incorrect, but I am thinking there is a more refined way of doing this. And yes, each of thos obj*Create does represent a diff element which needs the behavior that is supplied by MAINFUNC.
Thank you.
var MAINFUNC = function(opts)
{
var m = Object.create(MAINFUNC.prototype);
m.options = { ... };
m.init(opts);
return m;
};
var o = [{someoptions}, {someoptions}, {someoptions}].map(MAINFUNC);
// objects are all now in array
A side benefit of this approach is it makes MAINFUNC work whether you use new or not. This makes it much more manageable, especially with collection functions.
Related
I have created two different independent scripts to update two different canvas. The problem is that some of the function names in both the scripts are same. This is going to result in conflicts.
I could combine them together to form a big script but that will soon become messy if I try to add more functionality. Similarly, naming every function differently will be tedious and error prone.
Is there some way, I can keep the scripts with same function names on a single page without any conflict?
Here is my code:
var DropEffect = {
var dropSize, speed;
var createDrops = function () {
var canvas = document.getElementById("drop");
....
};
}
This is the error I get:
Unexpected token name «dropSize», expected punc «:»
Try to do it like this:
File 1:
var nm1 = {
myFunction: function(){
}
}
File 2:
var nm2 = {
myFunction: function(){
}
}
Now, whenever you want to access, use nm1.myFunction() or nm2.myFunction();
In general such kind of objects are called namespaces.
After you modified question,
var DropEffect = {
var dropSize, speed;
var createDrops = function () {
var canvas = document.getElementById("drop");
....
};
}
This is not correct. You are creating variables inside an object (namespace).Objects just understand key-value pairs. Better do it like this,
var DropEffect = {
dropSize : "",
speed : "",
createDrops : function () {
var canvas = document.getElementById("drop");
....
};
}
and now use it as: DropEffect.dropSize etc.
You can wrap code in IIFE's like this:
(function(){
var theFunction = function(){
console.log('foo');
};
theFunction();
}());
(function(){
var theFunction = function(){
console.log('bar');
};
theFunction();
}());
So I have a bit of experience writing normal plugins to do whatever, but I want to move towards an object-based event-driven system that can be more dynamic and customizable for the end user. For the sake of my question I have written up a small plugin that simply highlights text on the $(selector).hover() event.
Here is the JS/jQuery:
(function($) {
var objs = [];
var defaults = {
color: "blue",
normal: "black",
onHover: function() {},
offHover: function() {}
};
var Text = function (settings, self) {
this.self = $(self);
this.color = settings.color;
this.normal = settings.normal;
this.show = function () { this.self.css( "color", this.color); }
this.noShow = function () { this.self.css( "color", this.normal);}
this.onHover = settings.onHover;
this.offHover = settings.offHover;
};
$.fn.myPlugin = function(opts) {
this.each(function() {
var settings = $.extend({}, defaults, opts);
$(this).data('index', objs.push(new Text(settings, this)) -1);
// I feel like this should be handled differently, maybe
// attach an event to the inside of the object?
});
this.hover(
function(e) {
objs[$(e.currentTarget).data('index')].show();
objs[$(e.currentTarget).data('index')].onHover();
}, function(e) {
objs[$(e.currentTarget).data('index')].noShow();
objs[$(e.currentTarget).data('index')].offHover();
});
};
}(jQuery));
Basically, this line...
(this).data('index', objs.push(new Text(settings, this)) -1);
...could be handled much differently and more efficiently. The problem is I need a global array that holds all objects generated by the plugin. So if I call the plugin twice on two separate 'p' tags, then there should be two objects in that array, so on so forth. Right now, that aspect is 'working' but I need to store a reference to what index that object is at by attaching an 'index' data type to the DOM element. This feels like a very wrong way to have an object oriented approach. So how can I, on an event, trigger the function...
myObject.show();
...where myObject is a reference to the element in the array that I want to highlight.
I hope my question is clear, it is a weird issue to describe I feel, but also a very powerful concept if it can be applied the way I am thinking of it. Let me know if anything is unclear and I would be happy to clarify.
In doing a bit more reading and trying to understand how object oriented programming works in respect to javascript, jquery and the DOM, I stumbled upon my own answer. Here is what the code looks like for anyone that may have been as confused as I was going into plugin development:
(function($) {
var defaults = {
color: "blue",
normal: "black",
onHover: function() {},
offHover: function() {}
};
var Text = function(opts, self) {
var settings = $.extend({}, defaults, opts);
this.self = $(self);
this.color = settings.color;
this.normal = settings.normal;
this.onHover = settings.onHover;
this.offHover = settings.offHover;
this.show = function () { this.self.css( "color", this.color); };
this.noShow = function () { this.self.css( "color", this.normal); };
};
$.fn.myPlugin = function(opts) {
this.each(function() {
this.text = new Text(opts, this);
});
this.hover(
function() {
this.text.show();
this.text.onHover.call();
}, function() {
this.text.noShow();
this.text.offHover.call();
});
};
}(jQuery));
The issue I was dealing with was an appropriate understanding of name space and closure, as well as what things you can and cannot do with DOM elements. I am not sure if this is the common way or not, but it is working very well for my uses and might work for yours.
I have a question about jquery and DOM manipulation. How do you handle with DOM controls for e.g.
I have to get value from text input so I could this in ways:
var SomeClass = function() {
var control;
this.setControl = function(c) {
control = c;
}
this.getValue = function() {
return control.val();
}
}
$(document).ready(function() {
var sc = new SomeClass(); // of course control could be passed in contructor as well
sc.setControl($('#CONTROL'));
console.log(sc.getValue());
});
OR
var SomeClass = function() {
var control = $('#CONTROL');
this.getValue = function() {
return control.val();
}
}
$(document).ready(function() {
var sc = new SomeClass();
console.log(sc.getValue());
});
what is your opinion? What is better or maybe this is pile of trash therefore what is the best solution. Plz dont send me to backbone, spine and so on Im interesed in only in jquery.
best!
EDIT:
do you separate logic from UI or you are mixing it?
more complicated example
in js file you have a class that uses text control and in the secound js file also you need values from this input. What you are doing? you just call everytime $('#control') or create a third js file where would be a separated "class" to manipulate this input?
It would make more sense to move the setValue() inside the constructor:
SomeClass = function(c) {
var control = c;
return {
getValue: function() {
return control.val();
}
}
}
var x = new SomeClass($('input'));
alert(x.getValue());
However, I'm not sure how valuable this kind of information hiding will be. Perhaps as some kind of view wrapper.
In many cases you wouldn't need this wrapper, so just:
var $x = $('input'); // keep reference to a bunch of <input> elements.
Working on creating a dirt simply MVC framework for one of my own projects. Rather than using one that is public, I decided to create one since my needs are very unusual.
I've got my structure down for the Controllers and Views, however, I'm having some issues creating my model structure.
This is what I have for my model structure:
model.models = function(args){
init: function(){
this.on_init();
},
on_init: args.on_init || noop,
data: args.data || {},
};
So then, I would call this as a basic formula for all of the models I want to create. For example, I want to create employees, notifications and some other models using this as a basic blueprint, then make some basic adjustments.
I call:
model.employees = new model.models({
on_init: function(){
//something specific
},
data: {
//defaults
}
});
And we're all good up to this point, but here is where I'm having troubles. Now, when I want to create my end result, the model, I cannot create a new object from an object.. it must be a function.
The only thing I can think of is creating a return function for the second method, but that renders some issues in itself. I have done some research looking at other MVC code, but I was unable to wrap my head around it.
Any help would be very much appreciated!
is this what you want ?
model.models = function(args){
var noop = function(){};
var o = {};
var init = args.on_init || noop;
var data = args.data || {};
init();
//handle other initialization
//o.a = xx;
//o.b = xx;
//o.c = data.xxx;
//....
return o;
}
then you can use the new, and it can't appear syntax error
Did a lot of fiddling, came up with this:
var blueprint = function(args){
return {
data: args.data,
on_init: args.on_init,
create: function(args){
this.on_init();
return {
data: this.data,
whatever: function(){
console.log(args);
}
};
}
};
};
var notifs = new blueprint({
on_init: function(){
console.log('init');
},
data: {
test: 'test'
}
});
var res = notifs.create('test');
console.log(blueprint);
console.log(notifs);
console.log(res);
It comes out with a main function that works, the notifs function is customizable for each individual object type, then calling the create method will create the end method.
Boom!
I've a page that is generated dynamically, and that includes certain number (user-dynamically-defined) of advanced scatter plot charts. I intend to create a JavaScript object which defines the scatter plot itself, i.e. which takes some parameters, some data, and some container ID, and which will create the various elements needed to obtain the visualisation: canvas elements, toolbar, etc.. To do so, I started with the following (simplified) class:
(function () {
if (!this.namespace) { this.namespace = {};}
this._instances = { index: 0 };
this.namespace.ScatterPlot = function (containerId, file, options) {
_instances.index ++;
this.id = this.containerId+"-"+_instances.index ;
this.containerId = containerId ;
_instances [this.id] = this;
// ... Do stuffs with file and options ...
// Initialize elements once the DOM is ready
$(this.updateDOM);
}
namespace.ScatterPlot.prototype = {
updateDOM: function() {
$("<canvas>")
.click(clickCallback)
.appendTo("#"+this.containerId);
//(...)
},
clickCallback: function() {
alert("Some click: "+this.id);
}
}
})();
Each object can be created with:
var v1 = new namespace.ScatterPlot("container1", "foo", "foo");
var v2 = new namespace.ScatterPlot("container2", "foo", "foo");
There are two problems here: (1) in updateDOM, 'this' does not make reference to my initial ScatterPlot object, which means that this example will never work, and (2) similarly, the clickCallback will not be able reference the scatterplot with 'this' either.
I'm new to javascript, and I'm still struggeling to understand the logic of OO programming in javascript, so the question is: I'm I taking the wrong direction here ? After some digging, I could roughly achieve what I wanted by passing this to updateDOM:
$(this.updateDOM(this)); // This blows my eyes but does the trick, at least partially
updateDOM: function(that) {
$("<canvas>")
.click(that.clickCallback)
.appendTo("#"+that.containerId);
//(...)
},
clickCallback: function() {
// Not working either... Should pass 'that' to the function too
alert("Some click: "+this.id);
}
But I don't feel this patters to be very elegant... And the problem is not fixed either regarding the click callback.
Thoughts ?
Have a look at MDN's introduction to the this keyword.
The standard ways of dealing with that issue are using a that variable - not as an argument, but in a separate function:
var that = this;
$(function() {
that.updateDOM();
});
// or
$(this.getClickCallback());
...
namespace.ScatterPlot.prototype.getClickCallback = function() {
var that = this;
return function clickCallback(e) {
alert("Some click: "+that.id);
};
};
Alternatively, you can always use .bind() (or $.proxy for older browsers) which do quite what the second example does in a more generic way:
$(this.clickCallback.bind(this));