Hugoware

The product of a web developer with a little too much caffeine

Posts Tagged ‘Templating

CobaltMVC and Custom Selectors

leave a comment »

CobaltMVC is a server side templating framework that behaves just like jQuery for your Views. CobaltMVC also works in WebForms.

CobaltMVC supports a variety of CSS selectors including pseudo and attribute matching. To keep things flexible, I’ve made it so that you can create or overwrite anything built-in. This post we discuss how to create your own for your project.

Right now, if you wanted to select all of the even rows in a table then you could use the pseudo selector…

this.Find("table > :even");

Cool, but what if we wanted to create our own? Here is an example of a selector that finds ‘numeric’ HTML elements.


//called once to add it to the project
CobaltManagement.RegisterCustomPseudoSelector(
    "numeric", //the name of the selector :numeric
    (nodes, argument) => { //the comparison to use
        decimal container = 0;
        return nodes.Where(node => decimal.TryParse(node.InnerText.Trim(), out container));
    });

//then used from our pages like...
this.Find(":numeric");

You’ll notice there are two arguments for the method you provide – First is a list of the available nodes to compare against. The second is an optional ‘argument’ string. The method should return a list of nodes that should be kept in the selection.

And the argument? That is an optional value in case you want it included in your selector. A good example of using the argument is the nth pseudo selector which returns every x number item.

//Everything within the parens is included as part of the argument
this.Find(":nth(4)");

Note: The argument is passed as a string so you’ll need to perform any parsing before you begin using the value.

Attribute selectors match against the attributes of the HTML elements. CobaltMVC checks the values and makes sure that two string are passed (even if they are empty), but any additional parsing needs to be done as part of the method.

That said, the method you use to perform the comparison is slightly different.

CobaltManagement.RegisterCustomAttributeSelector(
    "%", //the prefix to use for the selector @attr%='value'
    (argument, value) => argument.Equals(value, StringComparison.Ordinal)); //the comparison

The special character is what you want to prefix the attribute selector with (if you plan to override the default = selector then you just pass in an empty string). This needs to be a special character so not to be confused with the name of the attribute.

The comparison method itself is just a pair of strings, the first being the argument provided by the user and the second being the value found on the attribute. If the element doesn’t have the matching attribute then it is skipped entirely.

So, we could use the method we created in the example above by using…

this.Find("[@title%='Hugoware']");

Pretty neat!

If you haven’t downloaded Cobalt then head out to GitHub and download the code!

Advertisements

Written by hugoware

June 6, 2010 at 11:08 pm

CobaltMVC – Custom Controls and Dynamic HTML

with one comment

CobaltMVC is a server side templating frameworks that works a lot like jQuery. You can use it with both ASP.NET MVC and WebForms – (Watch the introduction video)

So far all of the CobaltMVC examples that have been posted have involved selecting existing elements on the page and making changes to them. However, there are times you’d like to generate new elements or wrap the same markup in a reusable control and attach it to the page.

Controls in CobaltMVC are just CobaltElements with properties and methods that you can use to define the behavior of an element. Because of this, a control can be selected against and modified by external selectors. This means that any control can be adjusted and tweaked for your individual needs.

Want to learn more? Check out the screen cast below that explains some of the interesting things you can do with custom controls and dynamically generated HTML elements.

[Watch The Screencast!]

Written by hugoware

June 4, 2010 at 9:52 am

Cobalt Beta – jQuery Style MVC View Templating!

leave a comment »

In a recent blog post I shared a preview of the Cobalt project I’ve been working on. Today, the source code has been uploaded to git-hub and the first beta binaries are being released!

Not sure what Cobalt is? Watch a screencast showing how you can use Cobalt in your MVC projects.
Watch the video now!

If you’ve seen any of my previous blog posts then you realize I’m not much of a fan of the current way to populate templates in ASP.NET MVC. I’ve tried a handful of different ways to improve the experience but so far nothing really felt like an improvement.

Cobalt uses CSS selectors to find and update content, much like the way that jQuery works. Cobalt works *with* ASP.NET MVC (and WebForms) so you can include it in an already existing project and use it right away!

So what does Cobalt look like? Here is an example of an MVC View…

<%@ Page Language="C#" 
    Inherits="System.Web.Mvc.ViewPage<IEnumerable<ProductDetail>>" %>
<%  
    this.Ready(() => {

        //select by tag names
        this.Find("form")
            .Attribute(new {
                action = this.Url.Action("CheckOut")
            });
        
        //find and set values for elements
        string current = this.Find("h3").Text();
        this.Find("#title").Text(current.ToUpper());
        
        //select classes and certain pseudo selectors
        this.Find(".list :even").AddClass("alt-item");
        
        //create new elements on the fly
        var link = this.Create("<a/>")
            .Text("Read About Us")
            .Attribute("href", this.Url.Action("AboutUs"));
        this.Find("p").Append(link);
       
        //create custom elements (like CustomControls)
        Stylesheet sheet = new Stylesheet("~/site.css");
        sheet.AddToPage();
        
    });
    
%>

<html>
    <head>
        <title>Sample</title>
    </head>
    <body>
        <form method="post" >
            <h3>Temp Title</h3>
            <p>The description goes here</p>
            <ul class="list" >
                <li>Item 1</li>
                <li>Item 2</li>
                <li>Item 3</li>
                <li>Item 4</li>
                <li>Item 5</li>
            </ul>
        </form>
    </body>
</html>

You can see that much like jQuery we have to queue up the work we need to execute once the document is ready.

I have a lot of documentation to write and a lot of screencasts to record, but don’t forget about the preview video which should get you started. For now, here are a list of the more important details.

The Important Stuff!

  • You must call CobaltManagement.Initialize() in your Global.asax file in the Init method (just override it and call it).
    public override void Init() {
        base.Init();
        CobaltManagement.Initialize();
    }
    
  • Cobalt uses HtmlAgilityPack to handle parsing of html content. I’m not happy with the framework so it will be one of the first things to be phased out, but for now you need to make sure to download it if you get the source code instead of the binaries.
  • You must use this.Ready from your pages and controls to wrap your commands. Otherwise your commands will run before the document is ready and fail.
  • Cobalt is aware of context, so if you use this.Find within a UserControl then you’re only going to select elements within that control. If you need to access the Page level from a UserControl then you can call this.Page.Find to change the scope of the command.
  • Cobalt supports a decent amount of selectors. Below is a list of currently available options.
    • Combinators: ‘ ‘, >, +
    • Shortcut Attributes: #elementId, .cssClass, $elementName
    • Attribute Matching (ex. [@name=’value’]): equals (=), starts with (|=), ends with ($=), contains (~=)
    • Pseudo: first, last, even, odd, nth(#), lt(#), lte(#), gt(#), gte(#), text, password, button, checkbox, radio, submit, file

Keep in mind this is very much beta code – I was literally working on changes today :). If you’re feeling brave then download the source and dig right in!

Download Beta

Cobalt (Source Code)

Written by hugoware

May 31, 2010 at 11:38 pm

Cobalt MVC Preview!

with 3 comments

Lately, I’ve been working a lot on my project Cobalt which is, more or less, jQuery for server side ASP.NET MVC views. I’ve shown some code examples before but today I have a screen cast of some of the code in action.

Watch the video now!

Hopefully, I’ll have some code released in the next week or two, but for now feel free to give thoughts and feedback!

Written by hugoware

May 27, 2010 at 9:09 am

Using A Page Control For MVC Templating

with 2 comments

In previous posts I’ve talked about using WebControls along with ControlAdapters to have cleaner markup by using the built in ASP.NET page life cycle to assign values to the correct elements on the page. This approach can make views easier to read by removing server side code blocks and allowing logic to be handled within the code behind of the view and not within the page itself.

This post continues the discussion by looking at how you can use a Controller to create instances of views before rendering them to the page.

In previous examples, I used the View method as you normally would in MVC. This worked well enough – We had access to the Model property and the ViewData which gave us enough information to render our page.

However, this example approaches the same problem but a little differently. Instead, we are going to create the view and assign to the properties immediately and then render the content for the view. Below is some code that illustrates the idea.

//Keep in mind, this is sample code and needs more work
//before you plug it into a project but it should give a 
//general idea of how this could work.

using System;
using System.Web;
using System.Web.Compilation;
using System.Web.Mvc;

namespace MvcTemplating.Controllers {

    public class SampleController : Controller {

        /// <summary>
        /// Creates a new instance of a view 
        /// </summary>
        public T CreateView<T>(string path) where T : class {
            return BuildManager.CreateInstanceFromVirtualPath(path, typeof(T)) as T;
        }

        /// <summary>
        /// Renders a handler to the page
        /// </summary>
        public ActionResult Handler(IHttpHandler handler) {

            //update and process the handler
            this.HttpContext.Handler = handler;
            this.HttpContext.Handler.ProcessRequest(System.Web.HttpContext.Current);

            //quit handling this request
            this.Response.End();
            return null;
        }

    }

}

The Handler function takes care of performing the work for the view and then returns a null since the action is still going to be wanting a return value. If you know a better way to handle this please let me know. 🙂

Instead of reading values from the ViewData or the Model we can now just assign them directly to the view.

namespace MvcTemplating.Controllers {

    [HandleError]
    public class HomeController : Controller {

        //displays content using an instance of the view
        public ActionResult Index() {

            //create the view
            var view = this.CreateView<MvcTemplating.Views.Home.Index>("~/Views/Home/Index.aspx");

            //assign to properties
            view.LatestBlogPosts = BlogPosts.Recent(5);
            view.LatestTweet = TweetRepository.GetLatest();
            view.Title = "Welcome Visitor!";

            //and then show the view
            return this.Handler(view);
            
        }
 
    }

}

This sample requires we know the path to the view but that can be fixed by using standard path names or possibly scanning the site in advance and saving the paths in memory (which is something I’ve done before with UserControls)

This approach, combined with ControlAdapters, can result in clean markup and provide additional logical functionality for some of the more complex views in your existing MVC projects.

Of course, this is just “proof of concept” stuff… I’ll hopefully have more code to share before long.

Written by hugoware

April 25, 2010 at 11:00 pm

Using Code Behinds For MVC Templates

with 2 comments

I’ve done quite a few posts about using WebControls in MVC mostly as experiments to see if it was possible to bring WebForm functionality into a MVC application. It wasn’t really that I wanted to use WebForms in MVC but rather I still really like Controls having logical functionality. Sometimes a View is a little more complicated than simply inserting a value into the correct location on the page.

In my last blog post I gave an example that seemed impossible to do all within the render phase of the page but was easy to accomplish with a few WebControls. My controls didn’t have to dump out horrible markup or use the ViewState – They we’re simple and easy to use controls the rendered exactly the content I wanted to display.

So I’ve been working on a templating framework for MVC that can fit into an existing project without needing to start over that makes use of CSS Friendly Control Adapters – Remember those things?

Here is an example – (this is just some demo code and is missing some parts)

using System;
using System.Reflection;
using System.Web.UI;
using System.Web.UI.Adapters;

namespace MvcControlAdapters {

    /// <summary>
    /// Handles rendering controls to the page without IDs 
    /// and ensuring that DataBinding takes place on the page
    /// </summary>
    public class MvcControlAdapters : ControlAdapter {

        //perform data binding for the control
        protected override void OnLoad(EventArgs e) {
            (this.Control.Parent ?? this.Control).DataBind();
            base.OnLoad(e);
        }

        //create the HTML output for this control
        protected override void Render(HtmlTextWriter writer) {

            //clear this ID from view
            this.Control.ID = null;

            //check for an 'actualId'
            AttributeCollection attributes = this._GetAttributes();
            if (attributes is AttributeCollection) {
                attributes["id"] = attributes["_id"] ?? null;
                attributes.Remove("_id");
            }

            //perform normal rendering
            base.Render(writer);

        }

        //finds the attributes for a control (if any)
        private AttributeCollection _GetAttributes() {
            PropertyInfo property = this.Control.GetType().GetProperty("Attributes");
            return property is PropertyInfo
                ? property.GetValue(this.Control, null) as AttributeCollection
                : null;
        }

    }

}

Don’t compile and run just yet – You need to also add this XML to a new Browser File in your App_Browsers folder.

<browsers>
    <browser refID="Default">
        <controlAdapters>
            <adapter controlType="System.Web.UI.HtmlControls.HtmlControl" 
                adapterType="MvcWebControls.MvcControlAdapter" />
            <adapter controlType="System.Web.UI.Control" 
                adapterType="MvcWebControls.MvcControlAdapter" />
            <!-- snip... -->
        </controlAdapters>
    </browser>
</browsers>

The general idea behind this code is to attach an adapter onto any WebControl on the page and then either remove or replace the ID property with the correct value. This allows for the element to be referenced from the code behind but prevents the excessive ID from being displayed.

Keep in mind this is just a sample and won’t work exactly the way you’d like (for example, this doesn’t do anything about ‘name’ attributes on input tags).

In order to use this code we’re going to want to add a ViewPage that has a code behind that we can work with. You could add a script marked as runat=server at the top of the page but I don’t recommend it (which I’ll explain more of in a moment).

So here is a sample of what a page would look like now…

<%@ Page Language="C#" 
    CodeBehind="Index.aspx.cs" 
    Inherits="MvcAdapters.Views.Home.Index"  %>

<html>
    <body>
        <h1 runat="server" id="section" />
        <div runat="server" id="description" _id="desc" />
        <a runat="server" id="link" title="Check out the products!" >Learn More!</a>
    </body>
</html>

And then the code behind…

using System;
using System.Web.Mvc;
using MvcAdapters.Models;

namespace MvcAdapters.Views.Home {
    
    //the view for the page - STILL uses a Model
    public partial class Index : ViewPage<Product> {

        //prepare the content for the page
        protected override void OnLoad(EventArgs e) {

            this.section.InnerText = this.Model.Name;
            this.description.InnerHtml = this.Model.Description;
            this.link.HRef = this.Url.Action("Details", "Products", new { id = this.Model.ID });

        }

    }

}

And is finally rendered as…

<html> 
    <body> 
        <h1>Cheese Crackers &lt;3</h1> 
        <div id="desc">The best cheese crackers <strong>you've ever tasted</strong> - GUARANTEED!</div> 
        <a href="/Products/Details/18924" title="Check out the products!">Learn More!</a> 
    </body> 
</html> 

Which means we can assign the values for the model to the correct element on the page. We use properties like InnerText which will save us from calling Html.Encode or make logical changes to styles and attributes for elements without a mess of server side code blocks.

This might seem like an excessive amount of setup to populate content onto a page but it does have its advantages.

  1. Refactoring is easier – If a model is changed then the modification can be easily pushed into the rest of the project without requiring you to dig though server code blocks. (yes, you have precompilation but you’re still the one who has to change them.)
  2. View logic is cleaner – It is easier to write code to handle View logic outside of the view itself. For example, using a Visible property instead of an if-then statement wrapping HTML elements.

Of course, this might not make sense for every View, but the nice thing about this approach is that is works without needing to make a lot of changes to a project. This might make more sense in larger more complex views. Fortunately, an approach like this doesn’t require that you File->New Project to get it started.

Anyways, I’m still trying to decide what makes the most sense in this project so I’ll post more code as it moves along. Enjoy!

Written by hugoware

April 15, 2010 at 12:46 am