Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

#ifndef in javascript

I am looking for a solution to only define a function once in Javascript using something exactly like #ifndef in compiled languages. I found a couple of libraries that were supposed to mimic this functionality but they didn't work.

I am working with MVC 3 Razor and have defined some html helpers do put what are essentially user controls onto the page.

Each control has a set of javascript functions that define specific functionality for that control, so herein lies the issue: the functions get defined multiple times when the helper is called multiple times on a single page.

I am hoping to find a way to keep the very small amount of javascript defined within the helper and not have to divide all of the javascript for each of these small helpers in a separate file.

Sample:

@helper CmsImage(int id)
{
  var Html = ((System.Web.Mvc.WebViewPage)WebPageContext.Current.Page).Html;

  <text>
    <input type="button" class="editor_function" style="display: none;" onclick="editImage(@id); return false;" />
    <script>
        function editImage(id) {
            $('#alt_text' + id).attr('value', $('#' + id).attr('alt'));
            $('#image_url' + id).attr('value', $('#' + id).attr('src'));
        }

        function saveImage(button, id) {
            $(button).parent().parent().removeClass('color-yellow').addClass('color-red');
            $(button).parent().siblings('div.widget-content').html('<img alt="' + $('#alt_text' + id).val() + '" src="' + $('#image_url' + id).val() + '" id="' + id + '" />');
        }
        #endif 
    </script>
    Image Url:
    <input type="text" id="image_url@{id.ToString();}" /><br />
    Alt Text:
    <input type="text" id="alt_text@{id.ToString();}" /><br />
    <input type="button" value="save" onclick="saveImage(this, @{id.ToString();});" />
    @Html.Raw(GetCurrentContent(id))
  </text>
}

The above doesn't work in the browser, if gives me the error: '48: Unrecognized token ILLEGAL'

like image 709
KenEucker Avatar asked Sep 11 '11 03:09

KenEucker


3 Answers

As I presume you know, Javascript doesn't have preprocessor directives like C/C++, but you can use regular if statements that are evaluated at run-time like this:

if (typeof myFunc === "undefined") {
    var myFunc = function(a,b) {
        // body of your function here
    }
}

or for a whole library of functions:

if (!window.controlUtilsDefined) {
    window.controlUtilsDefined = true;

    // put control library functions here

    function aaa() {
        // body here
    }

    function bbb() {
        // body here
    }

}

or if you want to check based on some other variable:

var myFunc;
if (debugMode) {
    myFunc = function(a,b) {
        // body of your function here
    }
} else {
    myFunc = function(a,b) {
        // body of your alternate function here
    }
}

If your concern is just that you have multiple copies of the exact same function names in the library that each control uses, that isn't technically a problem in Javascript. The last defined one will be the operative one, but if they're all the same that isn't technically a problem. Only one definition will exist in memory as the later definitions will replace the earlier ones.

If you control the source of the controls, then it would be better to break the common utilities out separately into their own JS file and have the host page just include that utilities script file once.

Or (with a little more work but no additional responsibilities for the host page), each control could dynamically load their utlities from an external JS file and check a known global variable to see if some other control has already loaded the common external JS.

like image 101
jfriend00 Avatar answered Oct 16 '22 04:10

jfriend00


If you have some build script I suggest to use GPP preprocessor(http://en.nothingisreal.com/wiki/GPP, or win version http://makc.googlecode.com/svn/trunk/gpp.2.24-windows/)

So you need to do the following steps:

  1. gpp -o _script.js script.js (where _script.js - your source file with preprocessor commands)
  2. (OPTIONAL) minify script.js (using google closure compiler, etc.)
  3. deploy script.js to your web folder.

In this case you'll get the most optimized js code. And you do not need runtime checks

#define debugMode
#ifdef debugMode
    var myFunc = function(a,b) {
        // body of your function here
    }
#else
    var myFunc = function(a,b) {
        // body of your alternate function here
    }
#endif
like image 11
Max Avatar answered Oct 16 '22 02:10

Max


I see that that the answer provided by jfriend is a bit old when node.js is not around. Pls. check the latest preprocessor.js (available through npm install).

You can use the static conditions like below (from documentation)

 // #ifdef FULL
console.log("Including extension");
// #include "path/to/extension.js"
// #else
console.log("Not including extension");
// #endif

Usage is :


    Usage: preprocess sourceFile [baseDirectory] [-myKey[=myValue], ...] [> outFile]

    preprocess Source.js . -FULL=true > Source.full.js

like image 5
Sesha Kiran Avatar answered Oct 16 '22 02:10

Sesha Kiran