JavaScript File & Folder Structures: Just Pick One - February 2, 2012 by

Rails wants you to put specific files in specific folder structures, based on the object type that will be in the file. Java demands that files in a folder structure are namespaced by that folder structure. VisualStudio also makes it seem like file / folder names should be the namespace / class name as well – but that’s just a good suggestion and not a requirement. Other languages and frameworks have some requirements for how you organize your files, too… with the exception of browser based JavaScript (… mostly…)

JavaScript File Organization: You’re Doing It Right

The reality of JavaScript in general web-based development (not talking about server side at all, here) is that it makes absolutely no difference how your files and folders are organized. Zero difference at all… at least as far as the JavaScript runtime is concerned.

The only thing that matters is that you include your files in your HTML with a <script> block, correctly. You also need to pay attention to which order they are included in most cases, to make sure things are defined before they are used (tools like RequireJS and other script loaders and module definition / loaders help with this).

What does this really mean? It means:

You’re Doing It RIGHT!

Yup. You’re doing it right, because it doesn’t matter how you do it.

What does matter, though, is that you and your team (if you have a team) pick an organizational convention and stick with it. It’s actually very more important for your team to have a good file and folder structure for your JavaScript. But you don’t need to worry about what that structure is. Pick a standard and use it. When it fails (and it will), re-work your structure so that it works within the newly understood constrains and move on.

Of course, that fact that your browser and it’s JavaScript runtime don’t care about your file and folder organization doesn’t I’m without my opinions on how files and folders should be organized.

For example…

M, V and C Folders

A lot of people organize JavaScript MV* application files in a folder structure like this (BackboneJS in this case):

Screen Shot 2012 02 01 at 9 43 16 PM

To the best of my knowledge, this folder structure is based on the “models”, “views” and “controllers” folder structure that was popularized by Ruby on Rails. Sure others may have had it first, but it was Rails that made it popular. Other MVC framework followed suit and demanded that you put your controller objects in the controllers folder, your model objects in your models folder, etc. But unless you’re Rails (or another framework that wants to be like Rails), this folder structure is stupid.

I’m pretty sure that Rails uses this folder structure to assume the types of objects that are found within the files. And I know for sure that it uses file names to assume the class that will be defined within the file. That is, when rails sees a file called “/app/controllers/foo_controller.rb”, it expects to find a class called “FooController” and it expects that this class will inherit from some Rails controller base class. If these expectations are not met, errors are thrown to say so.

I understand why Rails does it this way: file and folder based conventions make it easy to assume what a file will contain, and that makes it easy for the runtime to optimize for performance when pre-loading and caching the code contained within the files. This makes sense to me in Rails because the convention is based on good ideas for optimizing the way Rails works and the way it looks for files and how it loads them.

But, unless you’re Rails or another framework that wants to assume certain files in certain folder contain certain code, this is a terrible way to organize files.

The Junk Drawer

There are some good examples of other standards along this line. For example, I tend to follow the convention of a “public” folder with “css”, “images”, and “javascripts” folders. But honestly, this folder structure exhibits many of the same problems of being stupid that organizing files in M, V, and C folders does.

The real problem with these types of folder structures is that they become junk drawers. Even DHH and the Rails core team recognize that this is a poor folder structure outside the confines of Rails+Ruby code. That’s one of the reasons they added the Asset Pipeline in Rails 3.1. DHH even called the “javascripts” folder a junk drawer, very directly, in a RailsConf keynote in 2011 (or was it 2010?) – complete with a slide showing a drawer full of junk.

With any application that moves beyond a trivial number of files, these content-type, mime-type, code-type and general type-based folder structures turn in to a bloated pile of junk that is very difficult to sift through. Who wants to look at a folder with 20, 50 or 100 files in it, when you only really care about 2, 5 or 10 of those files?

And what happens when you suddenly have an object type that doesn’t fit your pre-established conventions? You end with a “lib” folder, like Rails, which becomes the ultimate junk drawer. “It’s not a model? It’s not a controller? It goes in lib.” – no matter what the actual functionality contained within the file is. The “lib” folder is asking to be a junk drawer… demanding it, really. So, do you follow that same junk drawer convention for non-M, V or C type-based files in your JavaScript apps? That doesn’t any make sense to me.

How I Organize Files: By Functionality

I prefer to organize my JavaScript files the way I used to organize my C# files in .NET projects: by functional area of the application. That is, I group files together in folders based on the area of the application that they facilitate.

For example, my BBCloneMail application has the following folder structure for it’s JavaScript:

Screen Shot 2012 02 01 at 9 47 12 PM

Note that I’m still using the “javascripts” parent folder, but underneath of that I’m organizing by functional area of the application. In the root “javascripts” folder, are the primary application files – the ones that define the overall application bits. In the “mail” folder are all of the files that relate to the “mail” application. And, in the “contacts” folder are all of the files that relate to the “contacts” application.

I don’t care what “type” is contained in the file. That’s a completely irrelevant way to organize files to me. It makes no sense for me to organize files this way because many of my files contain more than one “type” of object. For example, I often put very simple model, collection and view definitions that are very closely related, in the same file.

Why Type-Based Folders Might Be A Good Idea

In spite of all my over-opinionated hand-waiving above, there are some good reasons to use type based folders in JavaScript. One reason is asynchronous file loading based on conventions.

You might have a JavaScript app that makes use of a templating engine (of which there are dozens, these days). It’s not always a good idea to pre-load every possible template in to the user’s browser, for download size and performance reasons. Sometimes it makes sense to fetch the template that you want the first time it’s requested.

To do this, it might make sense to use a convention to retrieve the files. I’ve seen several Backbone apps that use a jQuery selector to load files, as one example of this. When a Backbone view specifies a template as “#my-view-template”, the application’s template manager would make a request to the server to load something along the lines of “/templates/my-view-template.html”.

If you’re trying to organize your templates in a functional area of the application, you’ll have the added overhead of inserting the functional area folder name, such as “/mail/templates/inbox-template.html” for an “Inbox” view in a “mail” app, trying to load an “#inbox-template” jQuery selector as the template to render.

So… there’s at least one possible reason to use a type-based folder. I would still stick the type-based folder name under my functional area, though. I don’t want to mix up the templates between my functional areas of the application, by accident.

A Tradeoff: Folder Names vs File Names

Here’s one potential trade-off for using functional folder names vs type based folder names: you might have to specify the type in the file name. For example, if you have a model type name “Person”, a collection type named “Persons”, and a view to represent a single person or a collection of persons, what do you call that view? If you’re organizing things by type, you can call every “Person” and “Persons”

This can be very confusing. I was recently working with a client who was using an editor that only shows the file name for the open files, and none of the folder path for the files. He ended up with 4 “person.js” files in his open file list. Which one was the Person model, view, router, or controller file? We had to open each file to find the one we needed, every time. So, we took the hit on the file names. The “person.js” file contained the person model, while “persons.js” contained the collection, “personviews.js” contained the view definitions and “personrouter.js” contained the router. Thus, we’ve moved the need for specifying the object type from the folder structure (with all it’s bad ideas for using that) to the file name.

I’ve read at least one blog post that advocated using type-based folder names specifically to avoid the “ugliness” of having type names in your files. I seriously laughed out loud when I read that. Whether the type is in the file name or folder name is a moot point. You’re likely going to end up specifying the type somewhere. I would much rather have it in my file names because it’s easier for me to see things grouped together based on functionality, than based on the type of object contained in a file.

It’s Just An Opinion, And A Loose One At That

My own use of these conventions and ideas is rather loose at this point. I don’t stick strictly to anything, and I mix and match based on the project type, number of files and other constraints that a given project presents. Because, like I said at the top of this egregiously long post, you’re doing it right.

No matter what file and folder structure you pick for you JavaScript apps (assuming you’re using a suite of libraries that doesn’t force you in to a specific folder structure), you’re doing it right. JavaScript in a browser environment really doesn’t care what the file and folder structure is. But that doesn’t mean we as developers shouldn’t care. Pick a file and folder structure that fits the constraints of your application and change the structure as your app’s constraints change.


Los Techies

Modularity And Security In Composite JavaScript Apps - January 27, 2012 by

In one of my current apps for a client, I have an activity based security system that determines what the user is allowed to do. The trick to this system is that all of the authorization checks happen on the server, but the functionality that is being secured runs on the client, in JavaScript.

This is a bit of a problem. If I send all of the JavaScript that is uses to run any part of the system to the browser, then it’s possible that a clever user could enable it and do things they aren’t supposed to do. Of course, when they send a request back to the server, the server will verify they can do what they requested and block it… but the user should not be able to even try to do things they aren’t authorized to do, in the first place.

The solution that I’ve come up with, at a very high “functional area of the application” level, is simply not to send JavaScript to the browser if the user is not allowed to use it. This keeps me from having to do extra security checks in the browser, keeps the download for the user smaller and generally makes the app appear snappier because there is less code to run. More importantly, though, it keeps the user from being able to try things they can’t do.

Modules To The Rescue

I’m facilitating this through the use of modules in my JavaScript – both “module” as in the JavaScript module pattern, and “module” as in a packaged functional area of an application.

It’s worth noting, though, that I’m not using AMD (asynchronous module definitions), RequireJS, or any other “module” framework for JavaScript. The debate about the “right way” to do modules can rage on all it wants. I’m content with simple immediate functions and logical groupings of files while the more intelligent and invested people in the JS community figure that all out.

Each of the functional areas of my application is built in it’s own set of files. Each area has multiple files that it is composed within, but the files are grouped together for easy identification of what makes up a module. I also have an HTML template for each module which provides the needed <script> tags to include the code for that module.

Only Render What Is Needed

When I need a functional area of my site to be sent down to the user, I tell my server side template language to include the correct HTML file. For example, I’m doing this in an ASP.NET MVC application:

@{var user = (CustomPrincipal)User;}

@if (user.Can("locations/manage"))
{
    @Html.LocationManagementScripts()
}

@if (user.Can("locations/search"))
{
    @Html.LocationSearchScripts()
}
view raw
1.cshtml
This Gist brought to you by GitHub.

In this code, I’m checking to see if the current user is allowed to manage locations. If they are, the extension method “LocationManagementScripts” is called. This in turn renders the “LocationManagementScript.html” file at this point in my HTML layout. That file contains all of the <script> tags for the location management JavaScript app. In the same way, I’m checking to see if the user can search through locations, and running the same basic process if they can.

Self-Initializing Modules

When a functional module is included after passing one of these checks, it needs a way to get itself spun up and started so that it can do it’s magic. It may need to render something on to the screen. It may need to register itself with the application’s event aggregator, or any of a number of other things. This is where my Backbone.Marionette add-on comes in to play for my Backbone apps.

Marionette has an explicit concept of an “initializer” tied to it’s Application objects. When you create an instance of an Application object, you can call “app.addInitializer” and pass a callback function. The callback function represents everything that your module needs to do, to get itself up and running. All of these initializer functions – no matter how many you add – get fired when you call “app.start()”.

myApp = new Backbone.Marionette.Application();

myApp.addInitializer(function(options){
  var myView = new MyView({
    model: options.someModel
  });
  MyApp.mainRegion.show(myView);
});

myApp.addInitializer(function(options){
  new MyRouter();
  new SomeOtherView().render();
});

myApp.start();
view raw
2.js
This Gist brought to you by GitHub.

Each functional area of my application has it’s own initializer function. When a functional area has been included in the rendered <script> tags, the initializer gets added and when the “start” method is called, the modules for that functional area are fired up and they do there thing.

A Composite App, And Sub-Apps

One of the tricks to making all of this work, is that I need to have a primary “app” object that all of my modules know about. In the above example, the “myApp” object is this. Each of the modules for each of the functional areas has direct knowledge of this object and can call public APIs on it – including the “addInitializer” method.

A better example of what a module definition and initializer might look like, would be this:

// --------------------
// app.js

myApp = new Backbone.Marionette.Application();

myApp.addRegions({
  mainRegion: "#main"
});


// --------------------
// locationSearch.js

(function(myApp, Backbone){
  var SearchView = Backbone.View.extend({
    // ...
  });

  myApp.addRegions({
    searchRegion: "#search"
  });

  myApp.addInitializer(function(){
    var view = new SearchView();
    view.render();
    myApp.searchRegion.show(view);
  });
})(myApp, Backbone);


// --------------------
// index.html

<script language="javascript">
  myApp.start();
</script>
view raw
3.js
This Gist brought to you by GitHub.

In this example, I’m using the simple JavaScript module pattern to encapsulate my search functionality. I’m also providing an initializer for the module that instantiates a search view and shows it to the user using a region manager.

Each of these functional areas is basically a sub-application. Many sub-applications are used to compose a larger application and overall experience for the user. The composition of a larger application through various modules that are included / excluded based on some criteria are what really make this a composite application.

I also included the final call to “myApp.start()”, showing that I do this from my main HTML page and not from my JavaScript files. This provides a single point of entry for all of the registered modules, no matter which modules are registered. The “myApp” object really doesn’t care which modules are registered, honestly. It doesn’t need to care. It only needs to execute the initializers that happen to be present. If none are present because the user didn’t have permission to do anything, then nothing happens when this method is called and the user won’t see anything.

Security: Don’t Let Them See It If They Can’t Do It

If the security check to see if the user is allowed to use the location search feature fails, the rendered HTML won’t include the <script> tags for the “locationSearch.js” file. If this file is not sent down to the browser, then it will never register itself. If a module has not registered itself for initialization, it’s views won’t show up on the screen and the user won’t be able to try and use the feature. Further, the user won’t be able to “view source” on the page and find any stray JavaScript that they shouldn’t be able to use.

It’s Not Always That Easy

Of course there are other security concerns that are not this simple. When a functional area is closed off by authorization, it’s easy to keep things clean like this. We can compose the application at run time simply by including the right files and letting the code in those files register themselves for initialization. But when we have a functional area of the system that has finer grained authorization and permissions associated with it, things get a little more tricky.

I’m still learning and exploring this space. I have some ideas and am going to be implementing some of them soon. If anyone out there has any experience in handling finer grained security needs in JavaScript apps, I’d love to hear about it. Post links to your favorite resources for this, in the comments.

 


Los Techies

Composite JavaScript Applications With Backbone And Backbone.Marionette - December 20, 2011 by

Although I’ve mentioned it in this blog already, and have been tweeting about it, we’ll call this the official announcement for my new Backbone.Marionette library.

Backbone.Marionette: Make your BackboneJS apps dance with a composite application structure!

Why?

Over the last … however many months I’ve been using Backbone, I’ve developed a number of opinions around building apps. I have a particular style of code that I write, with a particular set of functionality that is common through most of (if not all of) my apps. Backbone.Marionette is another of the many plugins I’ve created, that encapsulates my opinions.

To date, i have the following libraries for Backbone, with more ideas in my head based on the work I’m currently doing:

My goal with these plugins is not to say “this is how you must work with Backbone”. Rather, I want to provide options and opinions for those that are running into the same problems that I’ve run into. When I find myself solving the same problem over and over again, I find myself wanting to extract the solution into a library. This lets me get on with my real application development instead of focusing on solving the same problem again.

The trick with my plugins, is to provide a set of libraries that all work independently, but can be combined in very creative ways to create some even more amazing. Even within each library, I’m trying to take an approach that allows you to use only the parts that you want. Of the three plugins I’ve written, I think ModelBinding is the most restrictive / hand-holding. Memento and Marionette both offer a great deal of freedom and flexibility vs the configurability of ModelBinding.

What?

Marionette is a library of tools that you can use when you want to, without being forced to use every single piece of it. These tools include:

  • Application initialization
  • View management
  • Event aggregation

Though the number of pieces is currently small, each of these pieces is very flexible and can be used without requiring any other piece. They can also be integrated into existing applications as-needed, allowing you to migrate an app from your existing code to Marionette.

How: Application Initialization

This was the big piece for me in building Marionette. I noticed that at some point that my BackboneJS applications tend to gather a cruft of procedural mess in an “application object”. This application object has always been responsible for starting up the various bits of the app: routers, initial views, instantiating collections and initial models, etc.

The problem is that these objects have usually ended up in a giant tangled mess with far too many concerns. For example, here’s some code from an image gallery that I wrote a few months ago. Note that this is only the application startup code:

ImageGallery.App = function(initialImages){
  var vent = _.extend({}, Backbone.Events);

  var images = new ImageGallery.Images(initialImages, {
    vent: vent
  });

  var mainView = new ImageGallery.MainView();

  var controller = new ImageGallery.Controller(images, mainView, vent);

  var router = new ImageGallery.Router({
    images: images,
    mainView: mainView,
    controller: controller
  });

  var showImage = function(image){
    controller.showImage(image);
    router.navigate("/image/" + image.id);
  }

  vent.bind("image:selected", showImage, this);
  vent.bind("image:edit:cancelled", showImage, this);
  vent.bind("image:edit:saved", showImage, this);
  vent.bind("image:deleted", function(){
    controller.home();
  });

  vent.bind("image:add", function(){
    controller.addImage();
    router.navigate("/add");
  });

  vent.bind("image:next", images.next, images);
  vent.bind("image:previous", images.previous, images);

  vent.bind("image:edit", function(image){
    controller.editImage(image);
    router.navigate("/edit/" + image.id);
  });

  this.initialize = function(){
    var imageListView = new ImageGallery.ImageListView({
      collection: images
    });
    $("#image-list").html(imageListView.render().el);

    new ImageGallery.MenuView({
      vent: vent
    });

    Backbone.history.start();
  }
}

view raw
gallery.js
This Gist brought to you by GitHub.

It’s a giant mess and it’s difficult to understand and maintain.

The solution involved recognizing that I was putting far too many concerns into a single place, combined with a healthy dose of encapsulation. I want each functional area of my application to have it’s own start up code, encapsulated within that functional area’s code. I don’t want to have to mash all the functional areas together into one procedural mess. So, I build the `Backbone.Marionette.Application` object.

This object provides a number of different features, one of which is the ability to register application initialization callbacks. To do this, you need to create an instance of an Application object, first. Then call the `addInitializer` method and provide a callback function. The initialization functions are then kicked off when you call the `start` method on your application:

// create your application instance
MyApp = new Backbone.Marionette.Application();

MyApp.addInitializer(function(){
  // do stuff here, to kick off your application
});

MyApp.addInitializer(function(){
  // more start up stuff here
});

// run all of the initializers!
MyApp.start();

You can optionally pass an object through the start method, as well. This object is made available to all of the initializer callbacks as a single parameter to the callback function. Additionally, there’s a “initialize:before” and “initialize:after” event that the application object raises, using Backbone’s Event functionality.

The trick is to keep your code organized and put your initializers next to the code that they initialize. Don’t just cram all of your initializers into a single file, recreating the same mess from my image gallery. Put your initializers near the code that they initialize. Keep them separate, keep it clean and decoupled. Add as many initializers as you need. Just remember that you have no guarantee of the order in which they run.

For more info on the application object, see the documentation.

How: Event Aggregation

The `Application` object comes with an event aggregator built into it. You can call the `.vent` property of any Application instance and have full access to the Backbone Event system. I won’t go into any more detail about this right now, as you can read up on the basics of how I use event aggregators in my previous blog post.

Of course you can still build your own event aggregator with one line of code.

var vent = _.extend({}, Backbone.Events);
view raw
vent.js
This Gist brought to you by GitHub.

In fact, this is all I’m doing in the Application object. I just put it there as a convenience so I don’t have to create one manually for every app:

How: View Management

In one of my recent blog posts on composite JS apps I talked about the use of a region manager, and the code that I wrote in that post has been migrated into Backbone.Marionette as the `RegionManager` object.

The intent and purpose of a RegionManager is the same as I’ve previously talked about. The difference in Marionette is how you access a RegionManager. You have two options: use the `addRegions` method on your Application instance, or manually create a RegionManager object. The choice gives you flexibility, allowing you to use a RegionManager without using the rest of Marionette, if you want to.

The `addRegions` method on the Application object accepts a single parameter of a JavaScript object literal. The keys for this object become the names of the regions, and the value of each key should be a jQuery selector that points to the HTML DOM element that your region manager will manage:

MyApp.addRegions({
  navigationRegion: "#navigation",
  mainRegion: "#main-content"
});
view raw
region.js
This Gist brought to you by GitHub.

You can also pass a RegionManager definition as a value. See the documentation for more info on this.

Once the application is started, each of the keys that specified will be available on the application object instance. You can then call the `show` method on your region managers to show your Backbone views in that region.

Documentation And Source Code

I’ve linked to the documentation several times, which is found on the Github repository that houses the code:

http://github.com/derickbailey/backbone.marionette

I also have the annotated documentation that I’ve previously talked about, available at:

http://derickbailey.github.com/backbone.marionette/docs/backbone.marionette.html

BBCloneMail: A Reference Application

In addition to the source code and documentation, I’m building a sample application that can be used as a reference for building Backbone applications with Backbone.Marionette. The name “BBCloneMail” comes from the idea of a “Backbone clone of GMail” to demonstrate a composite application. Though it’s styling is different than Gmail’s, you can clearly see the influence in the layout, the use of categories (labels) and the drop list to switch between the mail and contacts apps.

You can find BBCloneMail online at:

http://bbclonemail.heroku.com

The source code is here:

http://github.com/derickbailey/bbclonemail

And the annotated source as documentation is here:

http://derickbailey.github.com/bbclonemail/docs/bbclonemail.html

But Wait! There’s More!

This is the first official release of Backbone.Marionette: v0.1.0… I expect the functionality to continue to grow and evolve as I use it in more application, and as (hopefully) I see other people using it and contributing their own needs to the code.


Los Techies

Is There An Idiomatic Command Pattern Implementation For JavaScript? - November 19, 2011 by

I’ve been looking for a JavaScript Command Pattern implementation for a while now. If you google that term (or click that link) you’ll find a handful or more, that I simply don’t like. Granted, the implementations that I’ve found do work, but there’s always something about them that bothers me and makes me scream “NOOOO!!!!!!”.

So I’m wondering: is there a truly idiomatic JavaScript command pattern implementation available anywhere? Or do I just need to write my own?

In case there isn’t, I whipped up a simple stupid version of what it might look like if I were going to build one, in JSFiddle:

(Click on the link if you’re in an RSS reader)

You can see the code is simple, as I think it should be. Run the ‘Result’ tab if you’re reading this in the browser. Enter some text and click the “Say It” button. It does nothing more than show the text you entered. The point is not what it makes the app do, but how it does it. This provides a decoupled command pattern implementation, using JavaScript idioms like callback functions and key-value/hash/json objects to store registrations and all that jazz.

Of course there’s a lot missing from this code (like unregistering a command handler) and the core of this code is a very simple, stupid, single handler version of what’s already available in the Backbone.Events code – just with different semantics in the names of the methods.

So I ask – is there a good, idiomatic JavaScript implementation of a command pattern? One that allows proper decoupling of the command handler, command message and calling for the command to be executed? One that doesn’t rely on adding “class” semantics to JavaScript? One that doesn’t couple the name of the method being called as a command directly to the calling of the command (srsly… how could that even be called a command pattern?)?

Please let me know via the comments before I continue down the path of rebuilding something that I should be looking at / using.


Los Techies

JavaScript Has Built-In Mix-ins With ‘apply’ Or ‘call’ - October 7, 2011 by

While I was running the Object-Oriented JavaScript discussion / demo at Pablo’s Fiesta this weekend, Jimmy Bogard asked me to try something fun. I had a small constructor function defined with a couple of methods defined directly in it.

function Stuff() {
  this.whatever = function(){
    $("#results").text("whatever was called");
  }

  // ... other stuff here
}
view raw
1-stuff.js
This Gist brought to you by GitHub.

I also had an object literal with no methods defined, and was showing something (I don’t remember what, at the moment). Jimmy asked me to call ‘apply’ on the constructor function and pass my object literal into it.

foo = {};
Stuff.apply(foo);
view raw
2-apply.js
This Gist brought to you by GitHub.

Then he asked me to call one of the methods from the function constructor on my object literal instance.

foo.whatever(); // #=> "whatever was called"
view raw
3-whatever.js
This Gist brought to you by GitHub.

I expected this to fail, because I didn’t think the method would be around on my object literal. I was wrong, of course! Here’s that code running in a live JSFiddle (click the ‘result’ tab if you’re seeing the embedded version in this post).

CRAZY! … or… simply exposing how constructor functions actually work, exposing an easy way to do mixins with JavaScript?

Here’s what’s happening:

1) When I call the function using `apply`, the first parameter i used as the context of the call. Therefore, `this` inside of the function refers to the object that I’ve passed in to `apply`. When `this.someMethod = function(){…}` is called, ‘this’ is the object i passed in.

2) I’m allowed to add any function I want to any object I want at any time, simply by assigning the function to an attribute on the object. Therefore, when `this.someMethod = …` is called, it’s as if I was directly calling `foo.someMethod = …` directly.

With this in mind it seems that JavaScript has mix-ins built right in. There’s no need to use something like underscore.js’ `extend` method. But I wonder: are there any gotchas to this scenario? Anything that I need to watch our for? I’m going to have to play a little more to see what the effects are, what scenarios really work well and don’t, etc.


Los Techies

Silverlight Tip of the Day #15 – Communicating between JavaScript & Silverlight - March 26, 2011 by
Communicating between Javascript and Silverlight is, fortunately, relatively straight forward. The following sample demonstrates how to make the call both ways.

Calling Silverlight From Java script:

In the constructor of your Silverlight app, make a call to RegisterScriptableObject().This call essentially registers a managed object for scriptable access by JavaScript code. The first parameter is any key name you want to give. This key is referenced in your Javascript code when making the call to Silverlight.
Add the function you want called in your Silverlight code. You must prefix it with the [ScriptableMember] attribute.
In Javascript, you can now call directly into your Silverlight function. This can be done through the document object. From my example below: document.getElementById("silverlightControl").Content.Page.UpdateText("Hello from Javascript!"); where “silverlightControl” is the ID of my Silverlight control.
Calling Javascript From Silverlight:

Javascript can be directly called via the HtmlPage.Window.Invoke() function.
Example for both:

Page.xaml:

namespace SilverlightApplication
{
    public partial class Page : UserControl
    {
        public Page()
        {
            InitializeComponent();
 
            HtmlPage.RegisterScriptableObject("Page", this);            
            HtmlPage.Window.Invoke("TalkToJavaScript", "Hello from Silverlight");
        }
 
        [ScriptableMember]
        public void UpdateText(string result)
        {
            myTextbox.Text = result;
        }
    }

Default.aspx:

<script type="text/javascript"> 
        function TalkToJavaScript( data)
        {
            alert("Message received from Silverlight: "+data);
            
            var control = document.getElementById("silverlightControl");            
            control.Content.Page.UpdateText("Hello from Javascript!");
        }    
</script>

Page.xaml:

<UserControl x:Class="SilverlightApplication7.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml
    Width="400" Height="300">
    <Grid x:Name="LayoutRoot" Background="White">
        <TextBlock x:Name="myTextbox">Waiting for call…</TextBlock>
    </Grid>
</UserControl>

Read more: Silverlight Tips of the Day – Blog by Mike Snow

Posted via email from Jasper-Net

.NET Info