Dukes' Web Development Postings
-
Changes everywhere we look
There have been some big and exciting changes in the DNN community recently. In addition to some bittersweet personnel changes, DNN Corp has been working with the community to increase the ownership of the DNN Platform, bringing in community members to commit code directly into the project and to be part of the discussions of where the project is headed, as well as being more open in general about discussions and decisions. It's a very exciting time to be involved in the project. It's probably going to take a while for the community members to understand what it means that the community as a whole, and not just DNN Corp, own this project now, and for us to really behave like that's true, but I honestly believe that it's a real game-changer for where this project is headed. Let us know (via Twitter, DNN Chat, Community Voice, GitHub, JIRA, or the forums) what you're looking for, and how you expect it to happen, and we're going to work with you to make sure that the community is served by the platform as best as we can.
One of the big questions in front of the platform is where to go from a technical perspective, because Microsoft is in the business of changes as well. In May they announced the next version of the ASP.NET platform, which is a very ambitious project to rewrite the whole stack, to clear some of the cruft that has built up over the years, and which is getting in the way of having a lean & modern development experience. One of the really cool parts of that process is that Microsoft is letting the community in very early in the process. Their announcement included making the project sources public on GitHub, where the team is working directly day-to-day, while the project is still in (pre-)alpha readiness.
In addition to having access to the code, they're also engaging with the community in a number of channels, one of which is through the "ASP.NET vNext Community Standup," a weekly, public, live meeting where they discuss what's happening in the last week and answer questions from the community. I caught it for the first time yesterday, where they were talking about what's been happening with the Entity Framework rewrite (and they explained a bit about why that's included in the ASP.NET rewrite). One of the pieces that they emphasized was that this new stack is truly a new stack from the group-up, and should be considered version 1, even though it's a conceptual continuation, and so will be marketed as the next version (i.e. ASP.NET MVC 6, Entity Framework 7) to try to lessen confusion. That said, they're still expecting to have customers who don't want to be on the v1 stack (either because it's new, or because they haven't yet implemented a needed feature), and are planning to fully support the current stack "for the forseeable future." So, while the future is a world without WebForms, and, at the least, developer mindshare is going to be headed in this new lightweight, cleaner direction, the future of our current stack still has some long-term vision and direction.
So, the world may be melting, but there's no need to panic, so long as we're investing in a plan. And the great part is that, with DNN, the whole community is able to invest in that plan together.
-
DNN World 2012
I just returned from DotNetNuke 2012 and wrote up a review of the experience at my Engage Software blog.
-
Day of DotNetNuke Recap
This weekend was the Day of DotNetNuke in Charlotte, NC. I was there to present two session, along with three other Engage colleagues (Oliver Hine and Anthony Overkamp also presented). I was honored to be able to present on the Client Resource Management Framework and the Services Framework, two newer components in DotNetNuke (introduced in DNN 6.1 and 6.2, respectively).
Making Full Use of the Client Resource Management Framework
The slides are available to view at http://bdukes.github.com/Making-Full-Use-of-the-Client-Resource-Management-Framework/. This is a really exciting opportunity for skin and module developers to dramatically improve the performance of their components by letting DotNetNuke worry about managing our client resource (CSS and JavaScript) for us. The big takeaways here are to use the framework, and make sure you turn it on, if you’re a site administrator.
Designing a Mobile-Enabling API
New in the just-released DotNetNuke 6.2 is the Services Framework. This gives module developers a great way to create web APIs to allow accessing the modules’ data in new and exciting ways. This opens up new development models and new flexibility in 3rd party extension, as well as opening up the way to make your components easier to consume from a native smartphone application. The slides from this one can be viewed at http://bdukes.github.com/Designing-a-Mobile-Enabling-API/, and the example projects are in the repository (https://github.com/bdukes/Designing-a-Mobile-Enabling-API) as well.
Thanks to those who attended my sessions and the conference in general, it was a really well-designed day and great to see everyone who came. If you have any questions about my sessions (whether you attended or not), feel free to contact me via this blog or on twitter.
-
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. -
Why isn’t My Scheduled Task Executing?
A quick diversion from the JavaScript Common Difficulties and Misconceptions series (I have another post queued up, just need to write the sample code), for an issue I just ran into.
Created a scheduled task for DNN, but it’s sitting in the scheduler queue, just getting more and more overdue. Why won’t my task run?
Somehow I missed the constructor from the tasks I copied. Your task needs a constructor that takes a
ScheduleHistoryItem
to run via the scheduler. -
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.