1

Recently I was building a custom SXA component and I have made that by cloning the Default Event List Component given by SXA .

I have to get the data in json format from a controller and bind it with html structure. Can I do it using rendering variants? If yes, how? And if not, how can I use SXA to create the component?

Controller

namespace Feature.Events.Controllers
{
    public class EventsController : StandardController
    {
        private readonly IEventsRepository _eventsRepository;
        public EventsController(IEventsRepository eventsRepository)
        {
            _eventsRepository = eventsRepository;
        }

        protected override object GetModel()
        {
            return _eventsRepository.GetModel();
        }

        public override ActionResult Index()
        {
            return View("~/Views/Events/Event List.cshtml", GetModel());
        }

        public JsonResult GetEvents(string datasourceId)
        {
            var listItems = new List<Item>();
            if (!string.IsNullOrEmpty(datasourceId))
            {
                var datasourceItem = Sitecore.Context.Database.GetItem(new ID(datasourceId));
                if (datasourceItem != null)
                {
                    if (datasourceItem.Children.Count > 0)
                    {
                        var eventItems = datasourceItem.GetChildren();
                        var response = eventItems.Where(x => x != null).Select(x => new EventsModel
                        {
                            EventName = x.Fields["CustomEventName"].Value,
                            Presenter = x.Fields["PresentedBy"].Value,
                            EventStartDate = Sitecore.DateUtil.IsoDateToDateTime(((DateField)x.Fields["CustomEventStart"]).Value),
                            EventEndDate = Sitecore.DateUtil.IsoDateToDateTime(((DateField)x.Fields["CustomEventEnd"]).Value),
                            Location = x.Fields["City"].Value,
                            LearnMoreLink = HSHelper.LinkUrl(x.Fields["LearnMoreLink"])
                        }).ToList();
                        return Json(response, JsonRequestBehavior.AllowGet);
                    }
                }
            }
            return Json("", JsonRequestBehavior.AllowGet);
        }
    }
}

Repository

namespace Feature.Events.Repositories.Concrete
{
    public class EventsRepository : VariantsRepository, IEventsRepository
    {
        public override IRenderingModelBase GetModel()
        {
            EventsListModel eventsListModel = new EventsListModel();
            FillBaseProperties(eventsListModel);
            eventsListModel.EventItems = FillEventsProperties(eventsListModel);
            return eventsListModel;
        }

        public IEnumerable<EventsModel> FillEventsProperties(EventsListModel eventsListModel)
        {
            var listItems = new List<EventsModel>();
            var datasourceId = RenderingContext.Current.Rendering.DataSource;
            if(!string.IsNullOrEmpty(datasourceId))
            {
                var datasourceItem = Sitecore.Context.Database.GetItem(new ID(datasourceId));
                if(datasourceItem != null)
                {
                    if(datasourceItem.Children.Count > 0)
                    {
                        var eventItems = datasourceItem.GetChildren();
                        listItems = eventItems.Select(x => new EventsModel(x, eventsListModel.RenderingWebEditingParams)).ToList();

                    }
                }
            }
            return listItems;
        }
    }
}

Models

namespace Feature.Events.Models
{
    public class EventsModel : VariantsRenderingModel
    {
        public Item InnterItem
        {
            get;
            set;
        }

        public bool IsFromComposite
        {
            get;
            set;
        }

        public EventsModel()
        { }

        public EventsModel(Item item, RenderingWebEditingParams renderingParams)
        {
            this.InnterItem = item;
            base.RenderingWebEditingParams = renderingParams;
            base.IsControlEditable = !renderingParams.DisableWebEditing;
            this.IsFromComposite = renderingParams.SkipCommonButtons;
        }

        public string EventName { get; set; }
       public string EventDescription { get; set; }
       public string EventType { get; set; }
       public string EventDetailsLink { get; set; }
       public string Presenter { get; set; }
       public DateTime EventStartDate { get; set; }
       public DateTime EventEndDate { get; set; }
       public string Location { get; set; }
       public string CECredits { get; set; }
       public string LearnMoreLink { get; set; }
    }

    public class EventsListModel : VariantListsRenderingModel
    {
        public JObject EventItemsList { get; set; }

        public IEnumerable<EventsModel> EventItems
        {
            get;
            set;
        }

        public EventsListModel()
        {
        }
    }
}

View

@using Feature.Events.Models
@using Sitecore.XA.Foundation.MarkupDecorator.Extensions
@using Sitecore.XA.Foundation.RenderingVariants.Extensions
@using Sitecore.XA.Foundation.SitecoreExtensions.Extensions

@model Feature.Events.Models.EventsListModel

@{
    bool isVisible = (ViewData["eventListVisible"] == null || (bool)ViewData["eventListVisible"]);
    int index = 0;
}
@if (isVisible)
{
    if (!(Model.Rendering.DataSourceItem == null && !Html.Sxa().IsEdit))
    {
    <div @Html.Sxa().Component(Model.Rendering.RenderingCssClass ?? "event-list", Model.Attributes)>
        <div class="component-content">

            @Html.Sxa().RenderHeading(Model.HeadingTag, Model.DataSourceItem, "Title", Model.GetRenderingWebEditingParams())

            @if (Html.Sxa().IsEdit && Model.Rendering.DataSourceItem == null)
            {
                @Model.MessageIsEmpty
            }

            @if (Model.Rendering.DataSourceItem != null && !Model.EventItems.Any())
            {
                using (Html.Sxa().BeginEditFrame(Html.Sitecore().CurrentRendering.DataSource, "Event Empty", Model.IsControlEditable))
                {
                    <span class="is-empty-hint">@Sitecore.Globalization.Translate.Text("Create A New Event List")</span>
                }
            }

            @if (Model.Rendering.DataSourceItem != null)
            {
                <ul>
                    @foreach (EventsModel item in Model.EventItems)
                    {
                        {
                            Html.RenderPartial("EventListEvent", item, new ViewDataDictionary
                            {
                                { "cssClass", ListsHelper.BuildCssClass(index, Model.EventItems.Count()) },
                                { "variantFields", Model.VariantFields }
                            });
                        }
                        index++;
                    }
                </ul>
            }
        </div>
    </div>
    }
}



<script type="text/javascript">
    $(document).ready(function () {
        let datasourceItemId = $(".datasourceitem").val();

        $.ajax({
            type: 'POST',
            url: 'api/Sitecore/Events/GetEvents',
            dataType: "json",
            data: {
                datasourceId: datasourceItemId
            },
            success: function (data) {
                var len = data.length;
                var txt = "";
                if (len > 0) {
                    for (var i = 0; i < len; i++) {

                        txt = "<tr><td>" + data[i].EventName +
                            "</td><td>" + data[i].Presenter +
                            "</td><td>" + new Date(parseInt(data[i].EventStartDate.substr(6))) +
                            "</td><td>" + new Date(parseInt(data[i].EventEndDate.substr(6))) +
                            "</td><td>" + data[i].Location +
                            "</td><td>" + data[i].LearnMoreLink + 
                            "</td></tr>";
                        $(".event-content-wrapper").append(txt);
                    }
                }
                console.log("Success");
            }
        });


        $('.hidemonth').hide();
        $("#1-month").show();
    });

    $('div div a').click(function () {
        $('.hidemonth').hide();
        $("#" + $(this).attr('data-title')).show();
    });
</script>

I want to use the json data returned from the controller to bind with the html structure created by using the my custom rendering variants structure .

1 Answer 1

0

A SXA rendering can return html or json, but to use the variants system your model needs to have the data so the variants can access that and turn the data into html.

From a quick look at your code you need:

  • make sure your custom properties on the model are filled on the right place (you are now doing this in the GetEvents which is not the right place - your repository should do this to make sure the model is always filled correctly)
  • create a GetModel function (or similar) to return your model
  • create the variant and use Model (or Model Iterator) to access the non-Item data (or use Scriban if on 9.3)

More info on this approach here: https://ggullentops.blogspot.com/2019/03/external-model-data-SXA-variant-Sitecore.html

Note that this is not a solution that will actually output json from the controller. If you need that you cannot use the variants as those work on objects and not on json. I don't know why you would need the controller to output json to be transformed to html in the view - you will have to make a choice here. I would go for the variants and try to add whatever (javascript) was needed custom in the view.

Other option

After reading the comments, there might be another idea:

If you need search options - why not go with the ootb search components? You could use that, filter on events and even make the search facetted. The result view of the search can be altered by rendering variants so that fixes that issue as well. You can use the processSearchItems pipeline to extend the result items with the necessary custom properties.

2
  • I need the controller to output the json data because that json data will bind in the html structure and on the top of it there will be a search box which is used to search the events asynchronously (on key pressed). Jan 12, 2020 at 17:45
  • Added another idea to the answer.. might also not fit 100% but you'll also need to think about the cost of custom work and consider if it's really worth it.
    – Gatogordo
    Jan 12, 2020 at 20:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.