Search code examples
c#razorc1-cms

In Composite C1, is it possible to pass a page meta type field to a razor function?


I've looked through the C1 documentation and can't seem to find any docs or examples of passing a page meta type field to a razor function.

I'll give a very trivial example for a POC I'm doing.I've created a page with a page meta type that has a tag field. This tag field will be passed to a razor function that will query Flickr for all images tagged with the value contained in that field. I also don't want to configure this in the Razor function itself in case the Razor function is used on a page that does not use this page meta type.

Update

From what I can tell, you can't say use a constant or select a meta type field from the function parameters dialog, so instead I've just added a parameter that allows you to select the meta type field. See below.

@inherits RazorFunction

@functions {
    public override string FunctionDescription
    {
        get  { return "Some tweets based on keyword"; }
    }

    [FunctionParameter(Label="Flickr Data")]
    public DataReference<MyNamespace.Flickr> FlickrData { get;set; }

    [FunctionParameter(Label="Maximum tweets to show", DefaultValue = 5)]
    public int MaxItems { get; set; }
}

@{
    XNamespace atom = "http://www.w3.org/2005/Atom";
    var feed = XDocument.Load("https://api.flickr.com/services/feeds/photos_public.gne?tags=" + this.FlickrData.Data.FlickrTag);

    var items = feed.Descendants(atom + "entry").Take(this.MaxItems).Select(item => new {
        Title = item.Element(atom + "title").Value,
        Published = item.Element(atom + "published").Value,
        Markup = item.Element(atom + "content").Value
    });
}

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://www.composite.net/ns/function/1.0">
    <head>
    </head>
    <body>
    <p>
        @Html.Raw(@Resources.FlickrAtomFeed.FlickrFeedForMessage) <strong>@FlickrData.Data.FlickrTag</strong>
    </p>
        <dl>
            @foreach (var item in items) {
                <dt>@Html.Raw(@item.Markup)</dt>
                <dd>@item.Title
                    <em>@DateTime.Parse(item.Published).ToString("F"))</em>
                </dd>
            }
        </dl>
    </body>
</html>

From there if I want to use the function on a page, I just have to ensure that that meta type field is on that page. In fact if you try to add the function to a page without the meta type field, it will not let you save the function parameters, so it would be pretty clear that the meta type field needs to be on that page. Still not what I want, but it works.


Solution

  • In short, if your function is inserted on a page, you can:

    1. Get the current page ID. (Please see http://docs.composite.net/Functions/Composite-C1-API/Sitemap-Navigator)
    2. Query your meta type for the specific data item (the tag on this very page). (Please see http://docs.composite.net/Functions/Razor/Getting-C1-Data and http://docs.composite.net/Legacy/Razor/List-to-Details for inspiration)
    3. Process the retrieved data.

    The function can go like this (assuming your page meta type is "My.Meta.Type"):

    @using Composite.Data
    @inherits RazorFunction
    
    @functions {
        public override string FunctionDescription
        {
            get  { return "..."; }
        }   
    }
    
    <html xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://www.composite.net/ns/function/1.0">
        <head>
        </head>
        <body>
    
            @using (DataConnection dataConnection = new DataConnection())
            {
                // (1) get the current page ID
    
                SitemapNavigator sitemapNavigator = new SitemapNavigator(dataConnection);
    
                Guid PageId = sitemapNavigator.CurrentPageNode.Id;
    
                if (PageId != null)
                {
    
                // (2) Get the meta field from the current page
    
                    var myTag = Data.Get<My.Meta.Type>().Where(t => t.PageId == PageId).FirstOrDefault();
    
                // (3) Process the tag the way you like
    
                    if(myTag != null)
                    { 
                        <p>@myTag.Tag</p>
                    }
                }
            }
    
        </body>
    </html>