How to avoid a nested switch?

I am creating a context menu in JavaScript for a web application. The menu can be displayed in many contexts and have different options. I may have a different function for each context / selection:

grid1_delete() grid1_duplicate() grid2_delete() grid2_add() grid2_duplicate() 

and hardcode the ones used to create the menu. What I don't like about this is likely to be a lot of repetitive code. So I thought about using the dispatcher function, but this led to a potentially long, nested switch statement, like this:

 function contextMenuClick(context, menuItem) { var action = menuItem.innerHTML; switch (context) { case 'grid1': switch(action) { case('delete'): // do delete for grid1 break; case('duplicate'): // do duplicate for grid1 break; default: console.log('undefined action in contextMenuClick/grid1: ' + context); } break; case 'grid2': switch(action) { case('add'): // do add for grid2 break; case('delete'): // do delete for grid2 break; case('duplicate'): // do duplicate for grid2 break; default: console.log('undefined action in contextMenuClick/grid2: ' + context); } break; default: console.log('undefined context in contextMenuClick: ' + context); } 

Ugh. There has to be a better way. Maybe the dispatcher has more problems than it's worth. I reviewed some of the posts , but I don’t quite understand how to apply them to this particular situation.

+4
source share
4 answers

Switch statements are very rarely needed in Javascript. In general, you can simply use objects, such as dictionaries / maps, and search directly: foo.bar equivalent to foo['bar'] .

In addition, for the "global" variables, some_global_func() equivalent to window.some_global_func() , which can also be written as var f = 'some_global_func'; window[f]() var f = 'some_global_func'; window[f]() : you will never need eval to select a variable or call a function dynamically based on its name. In general, in doing so, you should prefer to store the function in the object, rather than in the global scope (i.e. in the window object).

So, if we assume that grid1_delete and grid2_delete fundamentally different and cannot be combined into a common function, you can do something like the following without changing your code:

 var grid_actions = { 'grid1': { 'delete': function() { /* ... */ }, 'duplicate': function() { /* ... */ } }, 'grid2': { 'delete': function() { /* ... */ }, 'add': function() { /* ... */ }, 'duplicate': function() { /* ... */ } } } function contextMenuClick(context, menuItem) { var action = menuItem.innerHtml; if (context in grid_actions) { if (action in grid_actions[context]) { grid_actions[context][action](); } else { console.log('undefined action in contextMenuClick/' + context + ': ' + action); } } else { console.log('undefined context in contextMenuClick: ' + context); } } 

The best solution, however, is to reorganize things to have these functions as object methods for each context, such as @ le dorfier .

+7
source

How do I pass the actual object reference in the context context instead of a string? Thus, you have only one switch statement:

 function contextMenuClick(grid, menuItem) { var action = menuItem.innerHTML; switch(action) { case('delete'): grid.delete(); break; case('duplicate'): grid.duplicate(); break; } } 

Even better, just bind the handler directly to the correct object / method.

+2
source

The simplest relief is that each switch has all the functions that contain the switch.

If you have an object for each of your contexts, you can add a function to each object that takes a menu as an argument.

+1
source

Something like using eval (context + "_" + action + "();") is likely to work, but is quite dangerous, as it will allow your client to execute an almost arbitrary function in your script. (everything that matches X_Y). Yes. eval is mostly evil.

What about

 switch(context+"_"+action) { case ("grid1_add"): grid1_add(); [...] } 
0
source

All Articles