Contents tagged with JavaScript
-
DNN World 2012
I just returned from DotNetNuke 2012 and wrote up a review of the experience at my Engage Software blog.
-
DNN World 2011
We’re on the plane flying back to St. Louis from DNN World 2011. I gave a presentation titled DNN 6 UI/UX Patterns, discussing the form patterns introduced in the administrative modules in DNN 6 (the new look and feel that you immediately noticed after logging into your new DNN 6 site). Many folks asked about seeing the examples that I presented, and they are available as a repository on github, at https://github.com/bdukes/DNN-World-Demos. This includes a series of small, one-control modules that demonstrate the various parts and pieces introduced in DNN 6. I’ve also placed the slide deck on SlideShare, (though the vast majority of the content was just demonstration, don’t be expecting a wealth of information there). Feel free to let me know if you have any questions, and I’ll do my best to give clarifications.
-
JavaScript: true, false, and in between
In JavaScript, all values can be coerced into a Boolean value (i.e.
true
orfalse
). Most values will evaluate totrue
, there are just a handful that will befalse
. Aside from the literalfalse
value, the number zero (0
), an empty string (''
),NaN
,null
, andundefined
all evaluate tofalse
in a Boolean context. All other values will evaluate to true (even an empty object ({}
) or an empty array ([]
) or ajQuery
selector that didn’t select anything). So, what contexts cause this Boolean evaluation? When am I actually going to see this in action?Most commonly, you’ll see this when using values in an
if
statement.var input = $('#text').val(); if (input) { // only do this if input is not an empty string }
So, when you see a non-Boolean value as the condition of an
if
statement, you can translate that in your head to “if that expression has a value,” so long as you remember that empty objects “have a value,” too. Pretty easy once you know what you’re seeing.Now, because all values can act as Booleans, operators that you might expect to return a Boolean result don’t necessarily have to return an explicit Boolean. As an example:
var text = ''; var index = 10; var hasTextOrIndex = text || index;
If the
||
operator was in the business of returning Boolean values, we might expecthasTextOrIndex
to betrue
; however, while it’strue
enough to get us into the body of anif(hasTextOrIndex)
statement, the actual value ofhasTextOrIndex
is10
. The definition of the||
operator is that it returns the left side if it can be converted totrue
, and otherwise returns the right side (&&
returns the left side if it can be converted tofalse
, and otherwise returns the right side). In the Boolean context, this behaves like the logical operators we’re used to, but lets us use them in non-Boolean ways as well. Most commonly, you’ll see||
used as a null-coalescing operator (like C#’s??
), saying “give me the left side unless it’sundefined
, otherwise give me a fallback value.” Less commonly, you’ll see&&
used to access an object’s property or method when that object might beundefined
(I don’t find it particularly readable, especially with methods, but it’s something you’ll see in the wild, if not something you’ll be using yourself).jQuery.fn.myPlugin = function (timeout) { var timeoutOption = timeout || 500; window.console && window.console.log('timeout is ', timeoutOption); }
The big caution here is to remember that
0
,NaN
, and''
are falsy values, so you need to be sure that0
isn’t a valid timeout value if you’re going to use the above example. Same thing goes withif
statements; remember, when you think “has a value” you need to think “isn’t undefined, zero, an empty string, or NaN or null”. -
JavaScript: this
JavaScript is a language steeped in juxtaposition. It was made to “look like Java,” yet is dynamic and classless. From this origin, we get the
new
operator and thethis
keyword. You are probably used tothis
referring to the current instance of a class, so what could it mean in a language without classes?In JavaScript,
this
refers to the object off of which a function is referenced when it is invoked (unless it is invoked viacall
orapply
). What this means is thatthis
is not bound to your function, and can change depending on how your function is invoked. It also means thatthis
changes when declaring a function inside another function (i.e. each function has its ownthis
), such as when writing a callback. Let's see some of this in action:var obj = { count: 0, increment: function () { this.count += 1; }, logAfterTimeout = function () { setTimeout(function () { console.log(this.count); }, 1); } }; obj.increment(); console.log(obj.count); // 1 var increment = obj.increment; window.count = 'global count value: '; increment(); console.log(obj.count); // 1 console.log(window.count); // global count value: 1 var newObj = {count:50}; increment.call(newObj); console.log(newObj.count); // 51 obj.logAfterTimeout();// global count value: 1 obj.logAfterTimeout = function () { var proxiedFunction = $.proxy(function () { console.log(this.count); }, this); setTimeout(proxiedFunction, 1); }; obj.logAfterTimeout(); // 1 obj.logAfterTimeout = function () { var that = this; setTimeout(function () { console.log(that.count); }, 1); }; obj.logAfterTimeout(); // 1
The last couple of examples here demonstrate some methods for making sure you get the values you expect. The first time
logAfterTimeout
is redefined, we usejQuery.proxy
to create a new function which has itsthis
permanently set to the passed in value (in this case, the currentthis
). The second timelogAfterTimeout
is redefined, we save the value ofthis
in a variable (namedthat
in this case, also often namedself
) and use the new variable in place ofthis
.Now, all of this is to clarify what’s going on when you use
this
. However, it’s pretty easy to avoid usingthis
altogether in your code (especially in the way I’ve demonstrated above). Instead of usingthis.count
all over the place, it would have been much easier if I’d madecount
a variable instead of a property, and then I wouldn’t have to usethis
to refer to it.var obj = (function () { var count = 0; return { increment: function () { count += 1; }, logAfterTimeout = function () { setTimeout(function () { console.log(count); }, 1); }, getCount: function () { return count; } }; }());
If you’re writing your code in this way, the main place you’ll run into issues with
this
is when handling DOM events (wherethis
is the element on which the event occurred). In that case, just be careful when using a callback within that event handler, that you’re not expectingthis
to still refer to the element (and useproxy
orthat
/self
if you need to refer to it).Finally, as demonstrated in the example, you can use
call
orapply
on a function to set itsthis
value. This isn’t often needed, but you may also want to know that you can useapply
to pass in an array of arguments to a function (e.g.console.log.apply(console, [1, 2, 3, 4])
). -
JavaScript: Global Variables
One of the biggest issues that you can run into with writing JavaScript is abusing the shared global namespace, and overwriting the variables of an unrelated script. Everything that you declare in JavaScript is available to every other script on the page, unless you wrap the declaration in a function. Also, if you use a variable without declaring it (even within a function), it will be declared for you in the global scope.
There are a couple of remedies we have against creating a global soup of conflicting variables. Knowing is half the battle, so step one is just keeping an eye out. Recognize when you’re creating a function or variable, and make sure that it’s not a global. The main technique for this is to declare everything inside a function. If you’re writing jQuery scripts, most of your script is probably being written inside the callback passed to
jQuery(document).ready()
, so you’re mostly safe already. If you’re not using a function already, you can wrap your code in an immediately invoked function expression.Step two is to catch when you miss declaring a variable. There are two ways to do this. The first is to turn on strict mode, so that browsers which support strict mode will throw an error when you try to access an undefined variable (instead of defining it as a global). In addition, you should be running your code through a linter (JSLint or JSHint) to catch issues like this.
So, now that you know how not to expose global variable, what about if you need to? If you need to write code in one script and reference it from another, you’ll need to expose a reference to that code somehow, right?
In this case, you should still probably be using all of the above techniques to keep the scope clean, but then explicitly expose anything that you need to. Again, if you’re using jQuery, this is fairly natural. Your script will take a reference to the global jQuery function, and you can add your script as a plugin to
jQuery.fn
. If you’re not exposing a jQuery plugin, you can take a reference to the globalwindow
object, and add your object explicitly. As an example:(function (window, $) { “use strict”; // turn on strict mode var x = 10; // x will not be accessible outside of this function y = x * 20; // y will be declared as a global variable, unless the browser supports strict mode $.fn.myPlugin = function (args) { ... }; // expose your plugin to the rest of the page window.textbox2_validate = function (sender, args) { ... }; // expose a standard function }(this, jQuery)) // immediately invoke this function expression, passing in this (a reference to the global scope) and jQuery
-
JavaScript Functions
When coming from a strongly-typed, object-oriented background, there may be some surprising elements when looking at how functions are used in JavaScript.
Functions in JavaScript don’t have any real concept of a signature, like they would in .NET. All functions return a value (which will be the value
undefined
if nothing is explicitly returned), so there are no void functions, and, while you can define named parameters for a function, callers of the function can provide more or less parameters than specified. If less parameters are provided, the other parameters will beundefined
, if more are provided, they are accessible via an implicit array-like variable namedarguments
. This also means that it’s not possible to have function overloads which have the same name and differ just by signature.There are also two different ways to create a function. The one that looks more like the object-oriented style is a function statement. This is a statement that starts with function, then gives the function name, parameter list, and body. One special characteristic of function statements is that they are defined throughout the entire scope of their containing function (i.e. they can be used before they are defined). They are said to be hoisted to the top of the containing function.
The other option is a function expression. This can look just like a function statement, but doesn’t require a function name, and is a value that can be assigned to a variable, passed to another function, or invoked. Let’s see some examples:
var myFunc = function (x) { if (typeof x === 'undefined') { return 'no args'; } else if (typeof x === 'function') { return x(); } else if (arguments.length === 1) { return 'x was ' + x; } else { return arguments.length - 1 + ' extra arguments provided'; } }, result1 = myFunc(), result2 = myFunc(function (y) { console.log(y); }), result3 = myFunc(statement), result4 = myFunc(1), result5 = myFunc({}, true, 'text'); console.log(result1, result2, result3, result4, result5); function statement(x, y, z) { console.log(x, y, z); }
So, we start here by defining a variable
myFunc
, whose value is a function expression. The function has one parameter,x
, and returns a string value indicating what was passed in. Forresult1
, we callmyFunc
without any arguments, and see thatx
isundefined
. Forresult2
andresult3
, we callmyFunc
with a function argument (forresult2
it’s a function expression, forresult3
it’s a reference to a function defined via a function statement), call that function, and return the result. Because both functions we pass in don’t return anything, the result isundefined
. Note that inresult3
, we were able to use statement before it was defined. Forresult4
, we callmyFunc
with one argument, and refer to the value via the parameterx
. Forresult5
, we callmyFunc
with more than one argument, and refer to thearguments
collection. -
Closure and Scope
The term closure refers to a function which references variables outside of its scope; the function is “closed over” those variables.
I’ll give an example of misusing closure in JavaScript and C#, then compare the solutions. This example is going to attempt the trivial task of outputting the digits 0 through 9.
JavaScript
for (x = 0; x < 10; x++) { setTimeout(function () { console.log(x); }, 1); }
C#
for (int x = 0; x < 10; x++) { setTimeout(() => Console.WriteLine(x) , 1); }
This assumes that a setTimeout method has been created for C#, just for the purposes of demonstrating this. In reality, you’ll run into this when you’re wiring up events with lambdas, iterating over LINQ queries, or using methods like List<T>’s ForEach.
The problem in these two examples is that the function passed to setTimeout is closed over the variable x; that is, we’re not referencing the value of x in the function, but the variable itself (similarly to a ref parameter in a C# method). By the time the function runs, x is 10, so the output to the console is actually 10 being output 10 times (see for yourself).
To fix this problem, we need to pass a new variable which always hold the correct value to each function. In C# this is pretty easy, because the for block provides scope.
for (int x = 0; x < 10; x++) { var closedX = x; setTimeout(() => Console.WriteLine(closedX) , 1); }
However, in JavaScript, only functions provide scope. If we tried this same technique in JavaScript, closedX would be the same variable in each run of the for loop (even though we’re using var to “declare” it). We need a new function to provide the scope to create separate variables for each run.
for (x = 0; x < 10; x++) { setTimeout((function (closedX) { return function () { console.log(closedX); } }(x)), 1); }
Here, we create a function which has one parameter, closedX, then immediately call it, passing in x. The parameter is a new variable for each run of the for loop because the function give it a scope, so it gives us the desired outcome.
Feel free to leave any questions in the comments, play with the example above on jsFiddle, and enjoy JavaScript to its fullest.
-
JavaScript: The Language
I gave my JavaScript language talk at the St. Louis .NET/DotNetNuke User Group last night. I’ve posted the presentation (with some updated, clarified example code) up on slideshare.
I woke up this morning thinking through all of the things that I could have explained better and how to more succinctly get the important points across. So, I’m now declaring (so that you, my loyal readership, can hold me to it) that I’m going to do a series on this blog focusing on illuminating common difficulties and misconceptions in JavaScript. Look forward to a discussion of closure sometime this week.
-
Chicago Day Of DotNetNuke 2010 Recap
Saturday, October 2nd was the Day of DotNetNuke in Chicago. A number of us from Engage attended and spoke. I gave two presentations, which are now available on SlideShare (linked below). I’ve added some notes (be sure to click the “Notes on slide 1” tab when viewing on SlideShare) to give context if you weren’t able to attend the session.
Considerations with Writing JavaScript in your DotNetNuke® site
Overall, we definitely were glad to participate in the event. The logistics were pulled off excellently (you certainly couldn’t tell that none of the organizers had organized an event of this magnitude before). I was also great to see the number of community leaders that were presenting and available. It really was a treasure-trove of DNN knowledge.
Nik Kalyani, the keynote speaker, did a great job of emphasizing the role that the community needs to play in guiding the development of DNN. A lot of us walked away excited about what we could contribute to move the community and platform forward.
Nik introduced the concept of a DNN Meme. This is an idea about DNN that catches on with the community in a way that it cannot be ignored. The basic idea is that if an idea is too good to resist, we need to share it so that something actually happens with it. Nik suggested that we use the hashtag #dnnmeme on twitter, and post bigger ideas to dnnmeme.com (via emailing post@dnnmeme.posterous.com). I’m not sure that the “DNN Meme” name is going to take off, but I can definitely get behind getting our ideas out there, gauging community interest, and pursuing the things that we all know that DNN needs.
In Nik’s session at the end of the day, we discussed a couple of things (documented on dnnmeme.com). The biggest of which was the need for module developers to get together and see where we can come to some agreements on how to implement our modules (whether that be a more standard set of markup/CSS, new features in the DNN core, or an agreement on how to implement large amounts of settings). Based on that discussion, Will Morgenweck created the DotNetNuke Module Standards project on CodePlex, where we can start the discussion of standardizing our approaches to modules.
If you are a module developer, we’d love your input on the patterns that you use when developing modules. Specifically, where you find yourself working around what the core provides, or find that the core doesn’t provide anything to support what you’re doing. We’ve gotten the discussion started with what we do and would like to do, but we need more voices so that we can come up with some real consensus on how to reconcile our different approaches.
-
Embedding JavaScript and Other Resources In a .NET Assembly
One concept that I don’t see people using, understanding, or even being aware of much in .NET development circles is the Embedded Resource. Declaring a file as an embedded resource within your project means that it will be compiled into the assembly, so that you don’t have to distribute the actual file with the assembly.
In our projects, we embed many of the resources that we use, in order to reduce the number of files that we have to distribute. The biggest use of this policy is towards JavaScript files. We use a lot of JavaScript in our modules, but we don’t have to distribute any .js files, they all live in a .dll. This also makes it a lot easier to automatically minify the JavaScript files when building, but that’s a story for another time.
Down at the end of this post, I’ll also talk about embedding files that are intended to be loaded in memory to be used, rather than accessed through the web. In that case, it’s much more convenient to already have the file in the assembly, rather than having to search through the file system for it.
So, how do you invoke this magic to place regular, non-compiled files into your compiled assemblies? It all starts, as many things do, in Visual Studio. With the file added to your project, take a gander at the file’s properties (by pressing F4 if you don’t have some crazy keyboard setup). The property page for a file is rather short, and we need to look no farther than the first property of the file to accomplish our purpose. The Build Action property of the file is usually set to Content, meaning “[the] file is not compiled, but is included in the Content output group.” By changing this to Embedded Resource, “[the] file is embedded in the main project build output as a DLL or executable.” This is most of the magic we need, but we’re not quite done yet.
Since this is a JavaScript file that we’ll want to access on the web, we need to tell the assembly that it’s okay to give the web access to the file. If you miss this step, you’re going to get an error page instead of JavaScript when you try to reference it (and everything that depended on the script will be throwing errors both left and right).
So, to accomplish this, we need to add an assembly-level attribute. These usually live in the AssemblyInfo file, which, by default, is under the Properties folder of your project. After adding a
using
/Imports
of System.Web.UI, we can add the following WebResource attribute to our project (given a default namespace of “Engage.Demos.EmbeddedResources” and the file “swfobject.2.1.js” placed in a “JavaScript” folder):[assembly: WebResource("Engage.Demos.EmbeddedResources.JavaScript.swfobject.2.1.js", "text/javascript")]
So, this brings us to the issue of naming. The file is assigned a name when it is embedded into the assembly. This name is the default namespace of the project, plus the folder path, plus the file name itself, all joined together with periods. One important thing to note is that VB.NET assemblies do not have default namespaces (they have root namespaces, a source of continual confusion and frustration for C# programmers who switch back and forth). Therefore, the resource names just start with the folder path. In this case, the name would be
"JavaScript.swfobject.2.1.js"
.Now that we’ve handled that, how do we actually get the script on the page? The same way you get any script on the page, you use the ClientScriptManager (you do use the ClientScriptManager to manage your client scripts, right?). This is accessible through the page’s ClientScript property, from which you can call RegisterClientScriptResource (when using an embedded resource, you don’t get to choose whether it is a “startup script” [added at the bottom of the page] or “script block,” [added at the top1] it’s always a “block”, so you can’t use the ClientScriptManager if you want to use this technique for a “startup script”).
The RegisterClientScriptResource method takes a Type and the name of the resource. The Type, as far as I can tell, is just used to provide an additional “namespace” for the include, i.e. trying to include the same resource twice with the same Type will result in only one script being added to the page, but if they have different Types specified, the script’ll be added twice. So, in our case (working with a class called DemoPage), this looks like the following call during the page’s Load event:
this.Page.ClientScript.RegisterClientScriptResource(typeof(DemoPage),
"Engage.Demos.EmbeddedResources.JavaScript.swfobject.2.1.js");One notable time where this won’t work is when you are trying to add a script to the page during a partial postback. In truth, you’ll probably have the same issue whether you’re embedding your JavaScript or not, but either way, the fix is to move from the ClientScriptManager to the ScriptManager (great naming for these two, don’t you think?). For embedded scripts, use the static RegisterClientScriptResource method like you would with a ClientScriptManager instance, otherwise, pick between RegisterClientScriptBlock, RegisterClientScriptInclude, and RegisterStartupScript. When using the ScriptManager methods, you’re required to add a line to the end of your script to notify the manager control that you’re script is done loading, but if your script is embedded into the assembly, it can do it for you and you’ll never have to wonder why the stupid thing isn’t working the way (you think) it’s supposed to work.
If you have a case where you want to add a reference to an embedded script but the provided methods don’t work for you, you can use the ClientScriptManager.GetWebResourceUrl method to get a URL to that resource that you can use anywhere URLs are accepted, worldwide.
Now, finally, what about files that aren’t JavaScript? What if you have an XML schema that you want to load up to valid XML against? Or what if you have an image that you want to add as a watermark to user-uploaded pictures? In those cases, when you really want to load up the file within memory, rather than expose it to the web, the workflow is rather different. At the most basic level, you’re going to use Assembly.GetManifestResourceStream to get a stream of the file. The easiest way to get an assembly reference is to start with the type you’re in, and then access its Assembly property, like so:
using (var schemaStream = typeof(DemoPage).Assembly.GetManifestResourceStream(typeof(DemoPage),
"Schemas.DemoSchema.xsd"))
{
// validate something...
}One further note about naming. In this situation, the first Type parameter is used to lend its namespace to the resource, so, in this case, since the full name of DemoPage is Engage.Demos.EmbeddedResources.DemoPage, I don’t have to specify the Engage.Demos.EmbeddedResources part of the resource’s name.
From there, you can go wild, doing whatever you want to do with the stream of your file.
Hopefully this clears some things up, and hopefully introduces you to a tool that you may not have known about or may not have known enough about. Make sure and let me know if you have any questions, or see any better ways to go about this stuff.
1 The ClientScriptManager actually only messes with the form element on the page, so it’s really the top and bottom of the page’s form that’s where the scripts get placed.