Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Backbone Marionette modules as Widgets similar to Twitter Flight

I'm reading up in choosing the correct client-side framework to segment/modularize my frontend code in Widgets.

Basically what I have/want is:

  • a complex website with multiple pagetypes, so no single-page application.
  • all pages are able to render a complete page WITHOUT the use of javascript. IOW: javascript is used as enrichment only.
  • Lots of pages have a very dynamic way in which widgets can be shown on screen. To overcome complexity at the server-side I've modularized my code into widgets (composite pattern), where each widget is responsible for it's own:
    • server-side controller code
    • server-side templating (using hogan/mustache)
    • routing endpoints, should it need to be called from the client
    • structural css (css converning the structure of the widget as opposed to the look&feel)
  • a server-side RegionManager ultimately decides which widgets are rendered and where they are rendered on screen. Endresults is that the RegionManager spits out the entire html (server-generated) as the composite of the rendering of all of it's widgets.

Now, some of these widgets DO have client-side logic and need rerendering on the client. Take a searchpage for instance, which needs to be able to update through ajax. (I've described this process, which uses DRY templating on client and server, here)

What I ultimately want is that, given I already use the composite pattern on the server, to extend this to the client somehow so that a Widget (1 particular logic block on the screen) contains all mentioned server-side code, plus all needed client-side code.

I hope this makes sense.

Would Marionette be suited to be used as a client side framework in this scenario? I'm asking since I'm not 100% sure if the concept of a Marionette Module is what I describe as being a Widget in above scenario. (I'm mentioning Twitter Flight in my question, since I believe this would be a fit, but it currently is so new that I'm hesitant to go with it at the moment_

I think basically what I'm asking is if anybody has some experience doing something along these lines.

like image 945
Geert-Jan Avatar asked Feb 26 '13 09:02

Geert-Jan


1 Answers

I think just using Backbone.js is perfect for this type of application you are describing. You have probably already read this, but most of the backbone literature is focused around your views having associated server generated JSON models and collections, then using the View's render function to generate (on the client) the HTML UI that represents the model/collection.

However it doesn't have to be used this way. In fact there is nothing stopping you attaching views to existing elements that contain content already, which gives you all of the benefits of Backbone's modularity, events system and so on. I often use views that have no model or collection, purely because I like the conformity of style. I have also used an approach like I describe below in the cases where I have had to work with older, existing applications that have not yet got, or never will have a nice REST API, but they do provide content in HTML.

Firstly, lets assume the following HTML represents one of your widgets:

<div id="widget">
    <div class="widget-title"></div>
    <div class="widget-body">
        <!-- assume lots more html is in here -->
        <a href="/Controller/DoWidgetStuff">Do something!</a>
    </div>
</div>

In this case, you could use backbone with a single Widget Model. This would be a very simple model, like this:

App.WidgetModel = Backbone.Model.extend({
    intialize: function () {
        this.url = this.options.url;
    }
});

Take note of the fact the Widget receives a URL as a parameter to its constructor/initialize function. This widget model would represent many of your widgets (and of course you could adopt this general approach with more complicated models and pluck different data from the rendered HTML). So next for your views. As you probably know, normally you pass most views a model or collection when you instantiate them. However in this case, you could create the Widget model in your View's initialize Function and pass it a URL from the pre-rendered HTML as follows:

App.WidgetView = App.View.ComboboxView = Backbone.View.extend({

    initialize: function () {

        this.model = new App.WidgetModel({}, { url: this.$("a").attr("href") });

    }

    // rest of the view code

});

So instantiating the view would be something like:

new App.WidgetView({el: $("#widget")})'

By doing all of the above you can do pretty much everything else that backbone offers you and its modular and encapsulated nicely, which is what you are after.

The end result of this whole approach is:

  1. You have rendered the Widget UI as pure HTML which (I assume) is functional without JavaScript.
  2. You attach a View to the existing HTML.
  3. You pass into the View as options, content by extracted (such as a URL) from the rendered HTML with jQuery.
  4. The View is responsible for instantiating the Model passing on the relevant options the model needs (such as a URL).
  5. This means all dynamic server side content is intially contained in the rendered HTML and your View is a modular JavaScript component that can do stuff to it, which I think is the end result you're after.

So you mentioned that you would like to have AJAX functionality for your widgets and that fine with this approach too. Using this approach, you can now use the standard Backbone fetch and save functions on the Widget model to get new content. In this example it is from the URL retrieved from the rendered HTML. When you get the response, you can use the view's, render function, or other finer grained functions to update the HTML on the page as required.

A few points:

The only thing to look out for is that you'll need to change the content type of the fetch and save functions to "text/html" if that's what the server is providing. For example:

this.model.fetch({
    type: "POST",
    contentType: "text/html"
});

Lastly, the model I have proposed is instantiated with no content. However if your ajax calls are a content type of "text/html", you may need to play around with you model so it can store this content in its attributes collection properly. See this answer for more information.

like image 70
dcarson Avatar answered Sep 27 '22 17:09

dcarson