A function and a form of encapsulation? - javascript

I'm sorry if this question has been asked before, but I'm not even sure what search terms to use to find the answer and when I try to search I never get anything specific to this question.
I'm using Javascript and I am wondering if it is possible to do something like this:
find(x); // find a document (for example)
find.inFolder(y); // find a folder's documents (for example)
In other words, can I have a function that can also be used as an object/class? I know I could run find() once and return a hash so that find.inFolder() would work, but I'm hoping there's a way where I could continue to call find().
Can it be done with prototype? (my "prototype" knowledge is very limited)
function find() {}
find.prototype.inFolder = function() {}
Can it be done inside a hash? [I know this code doesn't work]
var find = {
() : function() {},
inFolder : function() {}
}
To push it even further, is there a way to have the results of .inFolder() be sent to the find() function this way:
find().inFolder();
I know you might say that I don't understand the concept of javascript, and you'd be mostly correct, but I've seen people do some pretty amazing stuff with JS so I thought I'd ask the pros out there.
Thanks in advance for any help.

What you're describing is a Fluent interface (if you want something to search for). You could accomplish something like what you're trying to achieve like this:
var find = function() {
this.inFolder = function() {
return this; // Although to stop chaining, you could return nothing here.
};
return this;
};
find().inFolder(); // .inFolder().inFolder()...
This is a great pattern, especially when leveraged in projects like jQuery:
$("#element").find(".child_element").first();
Each call returns a jQuery object with .find(), .first() and many other functions, which lets you write intuitive and fluid code.
I kind of liked your find().inFolder() example, so here's an expanded version:
var find = function(file) {
this.folders = {
"Documents": ["Foo.txt", "Bar.txt"],
"Downloads": ["File.exe"],
"Misc": ["Picture.jpg"]
};
this.file = file;
this.inFolder = function(folder) {
var files = this.folders[folder];
return files.indexOf(this.file) >= 0;
};
return this;
};
alert(find("Foo.txt").inFolder("Documents")); // True
alert(find("File.exe").inFolder("Downloads")); // True
alert(find("Picture.jpg").inFolder("Downloads")); // False
http://jsfiddle.net/andrewwhitaker/TCdTd/

You can assign, a function to a member of another function:
find = function(x) { .... }
find.inFolder = function(y) { ... }
jsFiddle.
I'm not sure I understand the question however.

Related

Binding multiple events to elements stored in variable

I know that puting reference of HTML element into the variable is a good practice if I need to reference to this element many times. But I run into the problem with this while making my project. How can I bind multiple and the same events to the elements which are stored into the variable?
For now I deal with it this way:
var producerEl = $("#js-producer");
var brandEl = $("#js-brand");
var seriesEl = $("#js-series");
bind(seriesEl);
bind(brandEl);
bind(seriesEl);
function bind($el) {
$el.on("keypress", function () {
// some code..
});
}
I need something like $(producerEl, brandEl, seriesEl).on...
var producerEl = $("#js-producer");
var brandEl = $("#js-brand");
var seriesEl = $("#js-series");
producerEl.add(brandEl).add(seriesEl).on("click", function () {
alert('hello');
});
If you are trying to keep your code readable, might I suggest this approach?
$("#js-producer, #js-brand, #js-series").on('keypress', function () { });
Hmm. If you're using these selectors only one, don't care about "I know it is good to". The best solution is the one provided by David Smith.
Anyway, jQuery is using the sizzle selector engine, who has it's own cache. You can ask for
$("#js-producer, #js-brand, #js-series")
the result would be cached and reused.

Is it good to have unique method names across your application?

I might have the same method name across different and disparate objects:
Frame.hide = function() {
//
}
Dialog.hide = function() {
//
}
Treasure.hide = function() {
//
}
Is it good to keep method names across the application unique, such as:
Frame.hideFrame = function() {
//
}
Dialog.hideDialog = function() {
//
}
The best efforts of an IDE such as Webstorm, can't differentiate between the 3 hide() methods in the top snippet. As our application is growing bigger and bigger (we are at around 80 classes now), it is becoming almost impossible to navigate around code sometimes because method names are the same, and refactoring becomes downright dangerous.
Well, that's a matter of taste really. I personally do not like repeating object names in the functions.
So I favor :
Frame.hide = function() {}
Frame.show = function() {}
Frame.validate = function() {}
over:
Frame.hideFrame = function() {}
Frame.showFrame = function() {}
Frame.validateFrame = function() {}
Your IDE should never force you to do things which might not be the preferable way, in such cases you might want to search for another IDE (Netbeans?)

Javascript OOP events

I want to create an object that can parse a certain filetype. I've looked at some of the files in the File API and I want my object to work about the same. So basically, what I want is this:
A function, called CustomFileParser. I want to be able to use it as the following:
var customFileParser = new CustomFileParser();
customFileParser.parsed = paresed;
customFileParser.progress = progress;
customFileParser.parse(file);
function parsed(event){
//The file is loaded, you can do stuff with it here.
}
function progess(event){
//The file load has progressed, you can do stuff with it here.
}
So I was thinking on how to define this object, but I'm not sure how to define these events and how I should do this.
function customFileParser(){
this.parse = function(){
//Do stuff here and trigger event when it's done...
}
}
However, I'm not sure how to define these events, and how I can do this. Anyone can give me a hand?
Javscript is prototype-based OOP language, not class-based like most other popular languages. Therefore, the OOP constructs are a bit different from what you might be used to. You should ignore most websites that try to implement class-based inheritance in JS, since that's not how the language is meant to be used.
The reason people are doing it because they are used to the class-based system and are usually not even aware that are alternatives to that, so instead of trying to learn the correct way, they try to implement the way that they are more familiar with, which usually results in loads and loads of hacks or external libraries that are essentially unnecessary.
Just use the prototype.
function CustomFileParser(onParsed, onProgress) {
// constructor
this.onParsed = onParsed;
this.onProgress = onProgress;
};
CustomFileParser.prototype.parse = function(file) {
// parse the file here
var event = { foo: 'bar' };
this.onProgress(event);
// finish parsing
this.onParsed(event);
};
And you can use it like so
function parsed(event) {
alert(event);
}
function progress(event) {
alert(event);
}
var customFileParser = new CustomFileParser(parsed, progress);
var file = ''; // pseudo-file
customFileParser.parse(file);
From what it sounds to me i think you need your program to look like this
function customFileParser( onparse , progress){
this.onparse = onparse;
this.progressStatus = 0;
this.progress = progress;
this.parser = function (chunk)
}
this.parse = function(){
// Do stuff of parsing
// Determine how much data is it
// Now make a function that parses a bit of data in every run
// Keep on calling the function till the data is getting parsed
// THat function should also increase the percentage it think this can be done via setTimeout.
// After every run of the semi parser function call the progress via something like
this.parser();
if(progressStatus <100){
this.progress(this.progressStatus);
}else{
this.parsed();
}
}
}
and u can create instance of that object like
var dark = new customFileParser( function () { // this tells what to
do what parsed is complete } , function (status) { // this tells what
to do with the progress status } ) ;
using the method i suggested. you can actually define different methods for all the instances of the object you have !

Advice needed... Javascript OOP/namespacing

right now i am at a point where i feel that i need to improve my javascript skills because i already see that what i want to realize will get quite complex. I've iterrated over the same fragment of code now 4 times and i am still not sure if it's the best way.
The task:
A user of a webpage can add different forms to a webpage which i call modules. Each form provides different user inputs and needs to be handled differently. Forms/Modules of the same type can be added to the list of forms as the user likes.
My current solution:
To make the code more readable and seperate functions i use namespaced objects. The first object holds general tasks and refers to the individual forms via a map which holds several arrays where each contains the id of a form and the reference to the object which holds all the functions which need to be performed especially for that kind of form.
The structure looks more or less similar to this:
var module_handler = {
_map : [], /* Map {reference_to_obj, id} */
init: function(){
var module = example_module; /* Predefined for this example */
this.create(module);
},
create: function(module) {
//Store reference to obj id in map
this._map.push([module,id = this.createID()]);
module.create(id);
},
createID: function(id) {
//Recursive function to find an available id
},
remove: function(id) {
//Remove from map
var idx = this._map.indexOf(id);
if(idx!=-1) this._map.splice(idx, 1);
//Remove from DOM
$('#'+id+'').remove();
}
}
var example_module = {
create: function(id) {
//Insert html
$('#'+id+' > .module_edit_inner').replaceWith("<some html>");
}
}
Now comes my question ;-)
Is the idea with the map needed?
I mean: Isn't there something more elegant like:
var moduleXYZ = new example_module(id)
which copies the object and refers only to that form.... Something more logical and making speed improvements?? The main issue is that right now i need to traverse the DOM each time if i call for example "example_module.create() or later on any other function. With this structure i cant refer to the form like with something like "this"???
Do you see any improvements at this point??? This would help me very much!!! Really i am just scared to go the wrong way now looking at all the stuff i will put on top of this ;-)
Thank You!
I think you're looking for prototype:
=========
function exampleModule(id)
{
this.id = id;
}
exampleModule.prototype.create = function()
{
}
=========
var module1 = new exampleModule(123);
module1.create();
var module2 = new exampleModule(456);
module2.create();

jQuery and "Organized Code"

I've been struggling lately with understanding the best way to organize jQuery code. I asked another question earlier and I don't think I was specific enough (found in this question here).
My problem is that the richer you make an application, the quicker your client side gets out of control. Consider this situation...
//Let's start some jQuery
$(function() {
var container = $("#inputContainer");
//Okay let's list text fields that can be updated
for(var i=0; i < 5; i++) {
//okay let's add an event for when a field changes
$("<input/>").change(function() {
//okay something changed, let's update the server
$.ajax({
success:function(data) {
//Okay - no problem from the server... let's update
//the bindings on our input fields
$.each(container.children(), function(j,w) {
//YIKES!! We're deep in here now!!
$(w).unbind().change(function() {
//Then insanity starts...
}); // end some function
}); //end some loop
} // what was this again?
}); //ending something... not sure anymore
}).appendTo(container); //input added to the page... logic WAY split apart
}; //the first loop - whew! almost out!
}); //The start of the code!!
Now this situation isn't too far from impossible. I'm not saying this is the right way to do it, but it's not uncommon to find yourself several levels down into a jQuery command and starting to wonder how much more logic can add before the screen begins to melt.
My question is how are people managing this or organizing to limit the complexity of their code?
I listed how I'm doing it in my other post...
Just want to add to what was mentioned previously that this:
$.each(container.children(), function(j,w) {
$(w).unbind().change(function() { ... });
});
can be optimized to:
container.children().unbind().change(function() { ... });
It's all about chaining, a great way to simplify your code.
So far, I do it like this:
// initial description of this code block
$(function() {
var container = $("#inputContainer");
for(var i=0; i < 5; i++) {
$("<input/>").changed(inputChanged).appendTo(container);
};
function inputChanged() {
$.ajax({
success: inputChanged_onSuccess
});
}
function inputChanged_onSuccess(data) {
$.each(container.children(), function(j,w) {
$(w).unbind().changed(function() {
//replace the insanity with another refactored function
});
});
}
});
In JavaScript, functions are first-class objects and can thus be used as variables.
Well, for one, having a good IDE that understands javascript can help tremendously, even if just to identify matching demarcations (braces, parens, etc).
If your code starts to really get that complex, consider making your own static object to organize the mess - you don't have to work so hard to keep everything anonymous.
var aCustomObject = {
container: $("#inputContainer"),
initialize: function()
{
for(var i=0; i < 5; i++)
{
$("<input/>").changed( aCustomObject.changeHandler );
}
},
changeHandler: function( event )
{
$.ajax( {success: aCustomObject.ajaxSuccessHandler} );
},
ajaxSuccessHandler: function( data )
{
$.each( aCustomObject.container.children(), aCustomObject.updateBindings )
},
updateBindings: function( j, w )
{
$(w).unbind().changed( function(){} );
}
}
aCustomObject.initialize();
In my opinion the method described by BaileyP is what I use to start off with then I normally abstract everything into more re-usable chunks, especially when some functionality expands to the point where it's easier to abstract it into a plugin then have it specific to one site.
As long as you keep the large blocks of code in a seperate file and coded nicely you can then end up with some really clean syntax.
// Page specific code
jQuery(function() {
for(var i = 0; i < 5; i++) {
$("<input/>").bindWithServer("#inputContainer");
}
});
// Nicely abstracted code
jQuery.fn.bindWithServer = function(container) {
this.change(function() {
jQuery.ajax({
url: 'http://example.com/',
success: function() { jQuery(container).unbindChildren(); }
});
});
}
jQuery.fn.unbindChildren = function() {
this.children().each(function() {
jQuery(this).unbind().change(function() {});
});
}
Somebody wrote a post on the similar topic.
jQuery Code Does not have to be Ugly
For instance, the author, Steve Wellens, suggests to not use anonymous functions, as it makes code harder to read. Instead, push the function reference into the jQuery methods, like so:
$(document).ready(DocReady);
function DocReady()
{
AssignClickToToggleButtons();
ColorCodeTextBoxes();
}
Another takeaway from the article is to assign a jQuery object to a concrete variable, which makes the code look cleaner, less dependent on the actual jQuery object, and easier to tell what a certain line of code is doing:
function ColorCodeTextBoxes()
{
var TextBoxes = $(":text.DataEntry");
TextBoxes.each(function()
{
if (this.value == "")
this.style.backgroundColor = "yellow";
else
this.style.backgroundColor = "White";
});
}
Stick some of the anon functions into global scope functions (or your own "namespace" object), especially the re-used functions, and it begins to look less like what you posted. Kind of like what you linked to.
I described my approach in your other post. Short form:
do not mix javascript and HTML
use classes (basically start to see your application as a collection of widgets)
only have a single $(document).ready(...) block
send jQuery instances into your classes (instead of using plugins)
Use http://coffeescript.com/ ;)
$ ->
container = $ '#inputContainer'
for i in [0...5]
$('<input/>').change ->
$.ajax success: (data) ->
for w in container.children()
$(w).unbind().change ->
alert 'duh'

Categories