I updated this Question, beacuse my Fiddles were not saved well -
I'm building an app that contain a serie of similar operations with a form.
Instead of adding a lot of forms I chose to use a generic form and dynamically change the events on the buttons of the form.
My challenge is to make the code more generic, so I easily can add much more operations without multiplying the code. The complete non-generic code is in the Fiddle link, a part of that is placed here, under the link.
refined Fiddle
// sample
function init() {
operationA.addEventListener('mousedown', prepareA);
operationB.addEventListener('mousedown', prepareB);
}
// Operation flow:
// Prepare >> Cancel or Process >> Execute
function prepareA() {
if (isEventsRemoved) {
showForm();
ok.addEventListener('mousedown', processA);
cancel.addEventListener('mousedown', cancelA);
isEventsRemoved = false;
} else {
alert("Cancel other operation first");
}
}
function cancelA() {
hideForm();
cleanUp(processA, cancelA);
}
function processA() {
hideForm();
cleanUp(processA, cancelA);
if (input.value == "a") {
executeA();
} else {
alert("No good, try operationA again.");
cleanUp(processA, cancelA);
prepareA();
}
}
function executeA() {
alert("Executing A");
}
Instead of repeating the same functions/methods for A, B, C etc..
I started with generic functions, passing parameters for A, B ,C etc.
But when I follow this line, I don't know how to glue it together, some kind of recursiveness starts to appears, see the generic Fiddle. Again only part of the code under the Fiddle link.
Problem Fiddle
// Set it up
function init() {
operationA.addEventListener('mousedown', function(){ prepareAll(processA, cancelA)});
operationB.addEventListener('mousedown', function(){ prepareAll(processB, cancelB)});
}
// Operation flow:
// Prepare >> Cancel or Process >> Execute
function prepareAll(processHandler, cancelHandler) {
if (isEventsRemoved) {
showForm();
ok.addEventListener('mousedown', processHandler);
cancel.addEventListener('mousedown', cancelHandler);
isEventsRemoved = false;
} else {
alert("Cancel current operation first");
}
}
function cancelAll(processHandler, cancelHandler) {
hideForm();
cleanUp(processHandler, cancelHandler);
}
My question : Is this way really a dead end and should I for example use object instances instead of using generic functions with parameters, or am I just not following the way in the right manner ?
Related
I have two functions. I want this function:
function indentSpace(s, n){
return ((new Array(n+1)).join(s));
}
To get it's parameters from this function, while allowing this function to continue:
function onHandle(line, report) {
var input = $.trim(line);
if (parensBalanced(input) == false) {
indentSpace('.',input.length);
controller.continuedPrompt = true;
} else if (parensBalanced(input) == true) {
controller.continuedPrompt = false;
if (doCommand(input)) {
report();
return;
}
...
}
}
So that the 1st function gets used here, as the value for continuedPromptLabel:
$(document).ready(function() {
controller = $("#console").console({
continuedPromptLabel: indentSpace,
completeHandle: onComplete,
});
});
I've tried it several different ways, and it seems that once I get a value for indentSpace, it also returns that value in its containing function - and breaks other stuff.
Cheers!
So you want indentspace to essentially have a closure on its parameters from being called asynchronously from onHandle, such that onHandle is running freely, but then you want that indentspace with those parameters to be used elsewhere? I don't think that's possible.
I'm wondering if there is another way to write this function without using a modulo. I realized that I have another piece of code that requires me to click the #mail-wrap button and doing so messes up the number of clicks which affects this function.
It's just a simple switch. I'm not too good with conditionals.
$('#mail-wrap').click(function (e) {
e.preventDefault();
var c = 0;
if (c++ % 2 == 0) {
$('#contact-button').addClass('project-button').text('Projects');
} else {
$('#contact-button').removeClass('project-button').text('Get in touch');
}
});
Edit: Changed the question a bit. Sorry, the last one was too broad.
As Boldewyn mentioned, most likely your problem is that you are defining a global variable c. But if you would like to avoid this variable completely you could check for the CSS-class of contact-button via the jQuery hasClass function, i.e.
$('#mail-wrap').click(function (e) {
...
var contactButton = $('#contact-button');
if (!contactButton.hasClass('project-button')) {
$('#contact-button').addClass('project-button').css('width', '71px').text('Projects');
...
} else {
$('#contact-button').removeClass('project-button').css('width', '96px').text('Get in touch');
...
}
});
The code is interfering with other code, because you have implicitly generated a global variable c. Possible fix: Use an IIFE:
(function() {
var c = 0;
/* rest of your code above ... */
})();
I am a beginning JS programmer working through codeschool's 3rd JS course. One of their modules introduces the concept of passing function expression variables as parameters for other functions. However, I need some help understanding why this method is better in some cases than in others. For example, the following code is for a conditional alert that is supposed to recognize whether the user is a new user and throw a customized greeting when the user logs out of the system.
This is what codeschool advocates:
var greeting;
var newCustomer;
//Some code sets the variable newCustomer to true or false
if( newCustomer ){
greeting = function () {
alert("Thanks for visiting the Badlands!\n" +
"We hope your stay is...better than most.");
};
} else {
greeting = function () {
alert("Welcome back to the Badlands!\n" +
"Guess they aren't so bad huh?");
};
}
closeTerminal( greeting );
function closeTerminal( message ){ message();}
But why is that better than the following?
var greeting;
var newCustomer;
//Some code sets the variable newCustomer to true or false
closeTerminal();
function closeTerminal(){
if( newCustomer ) {
alert("Thanks for visiting the Badlands!\n" +
"We hope your stay is...better than most.");
} else {
alert("Welcome back to the Badlands!\n" +
"Guess they aren't so bad huh?");
}
}
Which of these code blocks (or any other code) would a good developer use to achieve the desired result? Is there an advantage to storing an entire function in a variable over just using a single if . . . else statement to evaluate newCustomer and return the desired greeting?
In your case, it is not inherently better.
But there are cases where it isn't this simple. Assume that you cannot modify the closeTerminal function, but its developer still wants you to execute arbitrary functionality from deep with his logic? That's where you use a callback function. Passing function expressions for them is only natural, but not strictly required. Have a look at purpose of callbacks in javascript maybe.
Another usecase for callbacks are asynchronous functions, you might encounter them later.
A better example might be
function closeTerminal(getMessage) {
var isNewCustomer = !Math.round(Math.random()); // complicated, local logic
var message = getMessage(isNewCustomer);
alert(message); // print to the closing terminal
// (which is local to this function as well)
}
You could invoke it with
closeTerminal(function greeting(newCustomer) {
// passing a custom function to determine the appropriate message
if (newCustomer)
return "Thanks for visiting the Badlands!\nWe hope your stay is...better than most.";
else
return "Welcome back to the Badlands!\nGuess they aren't so bad huh?";
});
Here's an example of their use:
function load_home() {
var url = "http://localhost/inner_load/page_test.html";
var method = "GET";
var postData = " ";
var async = true;
var request = new XMLHttpRequest();
/* Have a close look at this */
request.onload = function () {
var data = request.responseText;
Contenido.innerHTML=request.responseText;
}
request.open(method, url, async);
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
request.send(postData);
}
As you can see, I can specify a function that defines an action that will be performed when the server returns a result. Another example would be:
function add(a, b) {
return a+b;
}
function mult(a, b) {
return a*b;
}
function calculate(func, a, b) {
return func(a, b);
}
In this case I can choose what to do with the values passed as a and b by passing a function as a parameter, if I pass add, the two numbers will be added, if I pass mult, they'd be multiplied.
calculate(add, 10, 5);
Will return 15. Where:
calculate(mult, 10, 5);
Would return 50.
This would save you a lot of trouble if you are doing, say, a calculator. Instead of using an if … else block and some var storing some integer numbers or strings to define the operations you want to perform, you could just call the function giving the operation you'd want to perform.
The concept of scalability and reusability. With your code it definitely works. For now. Any change requested from client would require you to modify a hell lot of code. While maintaining such granularity with functions, allows you to write code that works and works well.
I myself haven't gone through any codeschool tutorials but you might find Functions chapter in eloquent javascript interesting. Here is a link you can use.
In your version of the solution, you will always greet the user with only alert box. The version in the tutorial gives the caller of closeTerminal method the flexibilty to pass any method which can contain any logic. i.e show message in alert or in a new jquery ui dialog or bootstrap dialog or a completely different logic.
Please see the following code to understand how we can reuse your logic.
HTML
<div id="myDiv"></div>
Javascript
var greeting;
var newCustomer;
//Some code sets the variable newCustomer to true or false
if( newCustomer ){
greeting = function () {
alert("Thanks for visiting the Badlands!\n" +
"We hope your stay is...better than most.");
};
}else {
greeting = function () {
alert("Welcome back to the Badlands!\n" +
"Guess they aren't so bad huh?");
};
}
function closeTerminal( message ){ message();}
function divGreeting(){
document.getElementById('myDiv').innerHTML = "Thanks for visiting the Badlands!\n" +
"We hope your stay is...better than most."
}
closeTerminal( greeting );
closeTerminal( divGreeting );
Working sample - http://jsfiddle.net/7P2Ct/
Here is the code that I have:
var criterion = _.extends({},Base);
criterion.dispatcher.on('save',this.saveIt,this); //respond to event save.
criterion.saveIt = function(){
if(this.hasChanged())
this.save({success:this.saveSuccess, error:this.saveError}); //method in Base
else
dispatcher.trigger('done');
};
criterion.saveSuccess = function() {
//do something
dispatcher.trigger('done');
};
criterion.saveError = function() {
//do something
dispatcher.trigger('done');
};
There are quite a few functions that end with dispatcher.trigger('done') for ajax specific items. This is used to update a progress bar on the web app - it counts down after receiving done events from every element either on success or error or when it was already in new state. Since the counter is deterministic it counts up by the number of items and counts down by the number of dones received.
Question: Is there a better way to remove the repeated calls to dispatcher.trigger('done') at the end of each function? Or is it a necessary evil. We have such code in various objects just to synchronize the execution of the 'next step' so to speak (think of it as a 'synchronization barrier').
You could make a method that appends the call automatically.
criterion.addProgressMethod = function( methodName, method ) {
criterion[methodName] = function() {
method();
dispatcher.trigger('done');
}
};
// usage
criterion.addProgressMethod( 'saveSuccess', function() {
// do something here
} );
I'm not sure if this is any better than what you've got, but it's an idea.
I've got a rather large plugin that I am currently writing in jQuery which is using a lot of internal functions that can accept varying arguments depending on the function.
I caught myself constantly writing the following in every function to stop the code from running if an argument hasn't been supplied or isn't valid:
add : function(args) {
if (args===undefined) return;
// function code;
},...
I was hoping that in a DRY type of sense it would be a good idea to write a little internal helper function that would do this for me.
Is this actually a good idea and most importantly what is the best/secure way to check for a varied range of acceptable arguments?
There are a lot of functions with multiple arguments in this plugin, for example:
load : function( filename , path , excludeFromRandom , callback ) {}
where filename is a string,
path is a string,
excludeFromRandom is a boolean and
callback can be a function or a string.
What is a good way to check for the existence and validity of these types of arguments without rewriting the same code over and over?
Any suggestions and ideas would be great.
Thanks for reading.
It depends to what extent you want to do this. In idea would be to create a validation function which takes a argument -> rule mapping. E.g.:
function foo(somestring, somenumber) {
var rules = {
'somestring': Validator.rules.isString,
'somenumber': Validator.rules.inRange(5,10);
};
}
Validator would contain the basic logic and some helper functions (rules):
var Validator = {
valid: function(args, rules) {
for(var name in rules) {
if(!rules[name](args[name])) {
return false;
}
}
return true;
},
rules: {
isString: function(arg) {
return (typeof arg === 'string');
},
inRange: function(x,y) {
return function(arg) {
return !isNaN(+arg) && x <= arg && arg <= y;
}
}
}
}
This is just a sketch, it certainly can be extended (like accepting multiple rules per argument), but it should give you some idea.
That said, you don't have to check every argument. Provide decent documentation. If people use your plugin in a wrong way, i.e. passing wrong argument types, then your code will throw an error anyway.
Update:
If want to do this very often, then a good idea is to write a wrapper function and you just pass the function and the rules to it:
function ensure(func, rules, context) {
context = context || this;
return function() {
if(Validator.valid(arguments, rules)) {
return func.apply(context, arguments);
}
return null; // or throw error, whatever you want
}
}
Then you can define your function normally as:
var foo = function(somestring, somenumber) {
// ...
};
and just add validation to it:
var rules = {...};
foo = ensure(foo, rules);
You could even consider to make ensure accept a callback which gets called on error or success of the function, instead of returning a value. There are a lot of possibilities.