How can I combine these functions - javascript

I'm learning about JavaScript functions and I've written three, which are basically identical:
function filterAll() {
location.hash = "/"
}
function filterCompleted() {
location.hash = "/completed"
}
function filterActive() {
location.hash = "/active"
}
Rather than having three functions, is it possible to combine them and call the paramaters that I need at that time through one function name? This is how I see it in my head, but I can't seem to work it out:
function filters(all, completed, active) {
all = location.hash = "/";
completed = location.hash = "/completed";
active = location.hash = "/active";
}
filters(all);

Using an object literal as a simple map lookup you could do this->
const actions = {
all: '/',
completed: '/completed',
active: '/active'
}
function filter(action) {
location.hash = actions[action];
}
//use like
filter('all');
filter('completed');
filter('active');
If you don't want to pass a string, another idea is using the map as an enum, to do this we could do these changes->
function filter(action) {
location.hash = action;
}
//use like
filter(actions.all);
filter(actions.completed);
filter(actions.active);
You could use lots of consts like #Rounin mentions, but I'm not a fan of making more variables, even if they are scoped.

I'm not sure what you're trying to do, can you add some notes.
If it's to pass three variables then your last code sample is fine.
IF its to pass one variable that has three data points, then use an object.
var filters = {all:"/", completed: "/completed", active: "active"};
then you can retrieve the values with (for example) alert(filters.all);

You can try this:
function filters(val) {
switch (val) {
case 'all':
location.hash = "/";
break;
case 'completed ':
location.hash = "/completed";
break;
case 'active':
location.hash = "/active";
break;
default:
break;
}
}

You can combine the three functions below into a single function which takes a single parameter.
Step One
First, set up three const variables:
const all = '/';
const completed = '/completed';
const active = '/active';
Step Two
Next, declare your function:
function myFilter(filterType) {
location.hash = filterType;
}
Step Three
Now you can invoke one function using different values:
myFilter(all);
myFilter(completed);
myFilter(active);

It looks like this is what you are looking for.
function filters(filterType) {
if (filterType == 'all') location.hash = "/";
if (filterType == 'completed') location.hash = "/completed";
if (filterType == 'active') location.hash = "/active";
}
Although I would not recommend using your functions like this, this is how you would use the function:
filters('all'); // Set all filters
filters('completed'); // Set completed filters
filters('active'); // Set active filters

First You will need to define those variables as constant, just to used as parameters(action).
You may use that code Below
function filters ( action ) {
return action==="all" ? location.hash = "/" : action==="completed" ? location.hash = "/completed": action==="active" ? location.hash = "/active" : "No Match Found";
}
To test the function i provided a simple example:
let tod = "all";
let com = "completed";
let act = "active";
//Here you will see all the information you need. You can run it in your browser.
[filters(tod),filters(com),filters(act)].forEach;

Related

Pure JavaScript "custom function" equivalent of $ jQuery

I don't want to use jQuery and I want to create a function that is similar to $ in jQuery.
Using code that is not a function is not suitable for what I want.
For example, we can use a code like this in jQuery:
$('.myClass').specialFunction();
Its equivalent in pure JavaScript is something like this:
document.querySelectorAll('.myClass').forEach(el=>{el.specialFunction()});
But this increases the size of the code. I am looking for a function that can execute something like this:
myfunc('.myClass').specialFunction();
If there is one element in myClass I can do this:
var myFunc=function(slct){
return document.querySelector(slct)
}
but if there are multiple elements in this class, what must we do?
It is not possible that return multiple elements from myFunc function.
and if using return document.querySelectorAll(slct) i can't call some JavaScript function such as addEventListener on returned object.
How to create such a myfunc function?
You might end up creating a new Library, but in short :
function $query(selector) {
if (typeof selector === 'object' && selector !== null) {
return selector;
} else {
let choice = selector[0]; // # or . etc
if (!['*', '.', '#'].includes(choice)) {
choice = '';
}
let selectorName = selector.toString().replace(choice, '');
switch (choice) {
case '#':
return document.getElementById(selectorName);
case '.':
return document.getElementsByClassName(selectorName);
case '*':
return document.getElementsByName(selectorName);
case '':
return document.getElementsByTagName(selector);
default:
return document.querySelector(selector);
}
}
}
// ### USAGE
let appDiv = $query('#app');
appDiv.innerHTML = `<h1>using ID</h1>`;
// TAG NAME
appDiv = $query('p');
appDiv[0].innerHTML = `<h1>using TagName</h1>`;
// CLASS NAME
appDiv = $query('.app');
appDiv[0].innerHTML = `<h1>using ClassName</h1>`;
// BY NAME
appDiv = $query('*app');
appDiv[0].innerHTML = `<h1>using Name</h1>`;
Try here at Stackblitz
You can add more features to it, depending on the need.
You can use prototype
You can also use this Build in Simple function:
document.querySelector(YOUR_Query);

Can I magically make the selectors non-functional if the selection value is empty?

Background:
I have a function that I call like this:
hide_modules('string1','string2');
The function is something like:
function hide_modules(param1,param2) {
MM.getModules()
.withClass(param1)
.exceptWithClass(param2)
.enumerate(function(module) {
module.hide(
// some other code
);
});
}
Most of the time I call the function with values as shown above.
Sometimes I do not want 'string1' to have a value and I'd like the my function to not use that first selector, effectively like this:
MM.getModules()
// .withClass(param1)
.exceptWithClass(param2)
.enumerate(function(module) {
module.hide(
// some other code
);
});
I've tried just calling it with an empty string, 0, false as param1 but the end result class selection is not what I want.
Sometimes I also call it with param2 empty and not wanting to have the param2 related selector used either.
So the question is:
Without writing a big if-then-else statement, is there some fancy way I can make those selectors non-functional (the equivalent of commenting it out like above) when the param1 and/or param2 values are not specified?
The supporting code that my function calls is provided for me in a 3rd party library that I can't change. I include some of the relevant parts here as it may help with the answer:
var withClass = function (className) {
return modulesByClass(className, true);
};
var modulesByClass = function (className, include) {
var searchClasses = className;
if (typeof className === "string") {
searchClasses = className.split(" ");
}
var newModules = modules.filter(function (module) {
var classes = module.data.classes.toLowerCase().split(" ");
for (var c in searchClasses) {
var searchClass = searchClasses[c];
if (classes.indexOf(searchClass.toLowerCase()) !== -1) {
return include;
}
}
return !include;
});
Since js doesn't supports function overloading, the only way is to validate your parameters inside your method. Check for truthy and ternary operator will do the trick
var modules = MM.getModules();
modules = param1 ? modules.withClass(param1) : modules;
modules = param2 ? modules.exceptWithClass(param2) : modules;
modules.enumerate(function(module) {
module.hide(
// some other code
);
});
to skip first parameter
hide_modules(null,'string2');
to skip second parameter
hide_modules('string1');

JS run function with in multi dim object failing.. not sure if this is even posisble

Ok, i have an attribue on a html element: data-content='from:function:project101.login.check'
I want to be able to run the function which lies within project101.login.check.
But with the js i have written i am not sure how i could achieve this.
At the moment the js get to the string but then cannot run it.
http://jsfiddle.net/3M7hC/
The html
<a href="some href" data-loader data-content='from:function:project101.login.check' >target</a>
The JS
var project101 = {
login: {
check: function(){
alert('function hit!');
}
}
}
$('*[data-loader]').click(function(e){
e.preventDefault();
var contentParams = $(this).attr('data-content').split(':');
console.log( contentParams );
switch( contentParams[0] ){
case 'from':
switch( contentParams[1] ){
case 'function':
contentParams[2]();
break;
}
}
});
Instead of using eval, you can split the string on . and drill down the object until you get to the place you need.
function getObjFromPath(path, context){
var obj = context || window,
pathArray = path.split('.');
for(var i = 0; i < pathArray.length; i++){
obj = obj[pathArray[i]];
}
return obj;
}
Then just call the function:
var func = getObjFromPath(contentParams[2]);
func();
DEMO: http://jsfiddle.net/SyFWh/
You may use it like
eval(contentParams[2])();
as what you get in contentParams[2] is just a string, and not a function object.
So eval(..) evaluates it to a js function, which can be eventually called.

add a wildcard to a JavaScript switch statement

is there a way i can create a switch statement with a wildcard with the logic of:
case: '/jobs/'+WILDCARD and ending in +'-jobs' :
this is for the window.location.pathname, which could be '/jobs/design-jobs', or '/jobs/engineer-jobs' etc
but, there are other pages which start with '/jobs' I don't want this to apply to, e.g '/jobs/post'
or any suggestions on a better way?
No there are not wildcards for switch statements, but you could e.g. use RegExp and test against it:
if( path.match(/^\/jobs\/(.*)-jobs$/) !== null ) {
//jobs url
} else {
switch( path ) {
case '/jobs/post':
//something else
break;
}
}
One trick you can use in some cases could be to use a function to normalize the input of your switch, to turn variable inputs into the specific cases:
Instead of:
switch(input) {
case 'something': // something
case 'otherthing': // another
case '/jobs/'+WILDCARD: // special
}
You could do:
function transformInput (input) {
if (input.match(/jobs.*-jobs/) return 'JOBS';
return input;
}
switch(transformInput(input)) {
case 'something': // something
case 'otherthing': // another
case 'JOBS': // special
}
You can do something like this:
var categories = {
design: function(){ console.log('design'); },
engineer: function(){ console.log('engineer'); }
};
for(var category in categories)
if(window.location.pathname === '/jobs/' + category + '-jobs')
categories[category]();

JavaScript - Per each case, make array

My last question asked for running once without the use of booleans. I decided I needed booleans but not a lot of variables since that would be messy.
So let's say I have this:
var counter = 0;
$(function() {
$('#typing').keyup(function() {
switch($(this).val().toLowerCase()) {
case 'test':
// DO THIS EVERYTIME TEST CASE IS CALLED
$('#test').fadeOut("fast", function() {
$(this).html("<span class='green'>That's correct!</span>").fadeIn("fast");
});
// DO THIS ONCE AND ONLY ONCE
count++;
}
});
});
Basically, it's part of 'percent complete' application where a user tries to type all cases I make available. So if a user types test twice... on the first run of case test it would add 1 to the counter but on the SECOND run of case test it would NOT add to counter.
I don't want to make it to add a lot of booleans for each case because that would be messy.
Get it? :)
My idea is to make an array and per each case that I add it would add alltogther. So array[0] would be case test. Then I on my first try I would set array[0] to 1.. then create a FOR-LOOP on each case array to add up for total. This is a good idea?
The only problem is I don't know how to make a per case array.
A simple way would be to use an object literal as the counter variable, and once a case is hit assign the value true:
var counter = {};
...
case 'test' : counter[$(this).val()] = true;
Alternatively, check if the 'case' has already been stored in a plain old boring array:
var counter = [];
...
case 'test' :
if(!$.inArray($(this).val(), counter)) {
counter.push($(this).val());
}
Doing exactly what you asked:
var validKeys = ['test', 'testing', '1337'];
var checkedKeys = {};
function getCount() {
var counter = 0;
$.each(validKeys, function(index, value) { //jQuery.each, for neat array iteration
if(checkedKeys[value])
counter++;
});
return counter;
}
$(function() {
$('#typing').keyup(function() {
var val = $(this).val().toLowerCase();
if(val == 'test') { //neater than a switch statement, often
// DO THIS EVERYTIME TEST CASE IS CALLED
$('#test').fadeOut("fast", function() {
$(this).html("<span class='green'>That's correct!</span>").fadeIn("fast");
});
}
checkedKeys[val] = true;
});
});

Categories

Resources