Shapes and Rendering

Topics: Core, Writing modules
Jan 4, 2014 at 9:54 PM
In one of the articles on developing modules for Orchard, I noticed something like that:
        public ActionResult Index()
            // Create a new shape using the "New" property of IOrchardServices.
            var shape = _services.New.ShoppingCart(
                Products: _shoppingCart.GetProducts().Select(p => _services.New.ShoppingCartItem(
                    ProductPart: p.ProductPart,
                    Quantity: p.Quantity,
                    Title: _services.ContentManager.GetItemMetadata(p.ProductPart).DisplayText)
                Total: _shoppingCart.Total(),
                Subtotal: _shoppingCart.Subtotal(),
                Vat: _shoppingCart.Vat()

            // Return a ShapeResult
            return new ShapeResult(this, shape);
Now the "ShoppingCart" Shape should have a corresponding CSHTML file. What about the properties of that Shape, like "ShoppingCartItem", shouldn't it also have a CSHTML file?

Or, is it just the Root Shape level should have a CSHTML file? It's not clear for me.

Jan 4, 2014 at 11:30 PM
Those that are shapes, such as ShoppingCartItem, need a template as well. You can tell that ShoppingCartItem is a shape because it is created through New.
Jan 5, 2014 at 7:45 AM
Very true.
However, only a template is provided for ShoppingCart shape and not the rest. At least in this module development series by Sipke.


Jan 5, 2014 at 8:55 AM
Perhaps that ShoppingCartItem shape is used as a view model holding some information, used in a foreach loop in the ShoppingCart shape template. You can verify this by looking at that template. As long as there's no Display() invocation trying to render the ShoppingCartItem shape, you don't need a template for it.
Jan 5, 2014 at 8:58 AM

Indeed. It's used only as Data.

As for ShoppingCart no driver is even written for it.

I'm trying to understand how Orchard handles Shapes. The root shape when returned by ShapeResult requires a template while those used as view model don't.

Jan 5, 2014 at 9:02 AM

Viewmodel could have been a normal collection right? Is it a must to have it collection of shapes?

Jan 5, 2014 at 9:26 AM
Edited Jan 5, 2014 at 9:27 AM
You don't create drivers for shapes, but for content parts. These drivers are one source of shapes, but shapes can be created from pretty much anywhere. The Driver infrastructure is a clever implementation to build a tree of shapes based on the content item and its parts to be rendered.

A shape only requires a template if you are handing that shape over to the Display() method. If you just use it as a bag of properties, no template is needed.

Yes, you're right, instead of using a collection of shapes, you could use a normal collection as you put it. I chose to use dynamic objects (shapes in this instance) because I thought it was very convenient to not have to write too many viewmodel classes.
You should realize though that the construction of shapes is not as fast as constructing classes. For one thing, the shape factory invokes handlers. I never did performance profiling, so I don't know if it's that bad. I never noticed a difference anyway.
Jan 5, 2014 at 9:38 AM
Edited Jan 5, 2014 at 9:29 PM
You are correct about drivers I mixed up. Shapes as far as I have noticed could be rendered as:
  • Display() method (either inline inside CSHTML or by returning ShapeResult)
  • Inserted inside Layout.cshtml
Relating to my question, the root shape returned by ShapeResult is handed in to Display() method and that's why it needs a template. The shapes used as data are simply kept as data. Correct ?