Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Morten Peter Hagh Jensen 25 posts 85 karma points
    May 24, 2021 @ 07:00
    Morten Peter Hagh Jensen
    0

    Return nested content items as JSON with controller

    I am trying to learn controllers and have searched a ton without finding a solution to my problem.

    I have some meeting dates and times created as nested content in nested content.

    The meeting dates being a nested content and the meeting times being nested content inside meeting dates giving a structure like this

    > date (24-05-2021) 
    >> 10:30
    >> 12:30
    >> 13:30
    
    > date (25-05-2021) 
    >> 11:30
    >> 14:30
    >> 15:30
    

    What I am trying to achieve is to create an endpoint with a Umbraco controller to get the times for a specific date chosen on a calendar on the front end.

    So if I f.x. select 25-05-2021 in the calendar, the click event should make a call to /umbraco/api/meetingdates/getdates/ with the date 25-05-2021 as the ID to select the content in Umbraco, like ?date=25-05-2021

    and return something like

    {
        date: "25-05-2021",
        times: [{
            "11:30",
            "14:30",
            "15:30"
        }]
    }
    

    The date item has the alias MeetingDateItemDay and the time item has meetingdateTimeItem with the overall property containing the items aliased meetingDatesAvailable

  • Huw Reddick 1740 posts 6102 karma points MVP c-trib
    May 24, 2021 @ 07:21
    Huw Reddick
    0

    Hi,

    Don't know if this will help at all, but this is something I wrote to export the metadata from pages.

    public JsonResult ExportMetaData()
    {
        int count = 0;
        List<string> pages = new List<string>();
        IPublishedContent homePage = Umbraco.Content(Guid.Parse("a53c075a-61a2-456e-a73d-e65e52efea92"));
        var pageNotes = homePage.Children;
        CountNodes(homePage.Children,ref pages, ref count);
    
        JsonResult ret = Json("{\"Synchronised\":[" + string.Join(",", pages.ToArray()) + "]}");
    
        return ret;
    }
    
    private void CountNodes(IEnumerable<IPublishedContent> children, ref List<string> pages, ref int count)
    {
        count += children.Count();
        foreach (IPublishedContent item in children)
        {
            if(item.Children != null)
            {
                var test = (PublishedContentModel)item;
                if (test.GetProperty("metaName") != null)
                {
                    pages.Add("{\"Id\":\"" + test.Id + "\",\"Name\":\"" + test.Name + "\",\"metaName\":\"" + test.GetProperty("metaName").GetValue().ToString() + "\",\"Description\":\"" + test.GetProperty("metaDescription").GetValue().ToString() +"\"}");
                }
    
                CountNodes(item.Children, ref pages, ref count);
            }
        }
    }
    
  • Morten Peter Hagh Jensen 25 posts 85 karma points
    May 24, 2021 @ 07:45
    Morten Peter Hagh Jensen
    0

    Just making a 1:1 copy of your code, which I would try to edit gives me

    cannot implicitly convert type system.web.http.results.jsonresult to system.web.mvc.jsonresult
    
  • Huw Reddick 1740 posts 6102 karma points MVP c-trib
    May 24, 2021 @ 08:17
    Huw Reddick
    0

    Change the signature of the method from jsonresult to actionresult, that should mix it :)

  • Morten Peter Hagh Jensen 25 posts 85 karma points
    May 24, 2021 @ 08:28
    Morten Peter Hagh Jensen
    0

    That unfortunately didn't do the trick :-(

    I have pasted my code here

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using Umbraco.Web.WebApi;
    using System.Web.Http;
    using HttpGet = System.Web.Http.HttpGetAttribute;
    using Umbraco.Web;
    using System.Web.Http.Results;
    using Umbraco.Core.Models.PublishedContent;
    
    namespace test_inspection_website.umbraco.Controllers
    {
        public class MeetingDatesController : UmbracoApiController
        {
            // GET: MeetingDates
            public ActionResult ExportMetaData()
            {
                int count = 0;
                List<string> pages = new List<string>();
                IPublishedContent homePage = Umbraco.Content(Guid.Parse("a53c075a-61a2-456e-a73d-e65e52efea92"));
                var pageNotes = homePage.Children;
                CountNodes(homePage.Children, ref pages, ref count);
    
                JsonResult ret = Json("{\"Synchronised\":[" + string.Join(",", pages.ToArray()) + "]}");
    
                return ret;
            }
    
            private void CountNodes(IEnumerable<IPublishedContent> children, ref List<string> pages, ref int count)
            {
                count += children.Count();
                foreach (IPublishedContent item in children)
                {
                    if (item.Children != null)
                    {
                        var test = (PublishedContentModel)item;
                        if (test.GetProperty("metaName") != null)
                        {
                            pages.Add("{\"Id\":\"" + test.Id + "\",\"Name\":\"" + test.Name + "\",\"metaName\":\"" + test.GetProperty("metaName").GetValue().ToString() + "\",\"Description\":\"" + test.GetProperty("metaDescription").GetValue().ToString() + "\"}");
                        }
    
                        CountNodes(item.Children, ref pages, ref count);
                    }
                }
            }
        }   
    }
    
  • Huw Reddick 1740 posts 6102 karma points MVP c-trib
    May 24, 2021 @ 08:32
    Huw Reddick
    0

    Does that give the same error?

  • Huw Reddick 1740 posts 6102 karma points MVP c-trib
    May 24, 2021 @ 08:33
    Huw Reddick
    0

    Ah, I see you are using an API controller, mine is in a surface controller so that explains the arror :)

  • Huw Reddick 1740 posts 6102 karma points MVP c-trib
    May 24, 2021 @ 10:12
    Huw Reddick
    100

    With an Api controller, you should just return a normal c# object or list, it will get returned either as xml or json depending on the request, so you can do something similar to below

    private List<Markers> GetLocations()
    {
        List<Markers> locations = new List<Markers>();
        var filePath = HostingEnvironment.MapPath("~/App_Data");
        using (var streamReader = new StreamReader(Path.Combine(filePath, "MapMarkers.csv")))
        using (var reader = new CsvReader(streamReader))
        {
            // the CSV file has a header record, so we read that first
            reader.ReadHeaderRecord();
    
            while (reader.HasMoreRecords)
            {
                var dataRecord = reader.ReadDataRecord();
    
                var loc = new Markers()
                {
                    Name = dataRecord["title"],
                    Id = new Guid(dataRecord["id"]), //Convert.ToInt32(dataRecord["id"]),
                    Description = dataRecord["description"],
                    Address = dataRecord["address"],
                    Link = dataRecord["link"],
                    Categories = dataRecord["category"].Split(','),
                    Geolocation = new Geolocation() { Latitude = Convert.ToDouble(dataRecord["lat"]), Longitude = Convert.ToDouble(dataRecord["lng"]) }
                };
                locations.Add(loc);
            }
        }
    
        return locations;
    }
    

    Obviously this isn't reading umbraco data, but the List is returned as a json array of marker objects

  • Morten Peter Hagh Jensen 25 posts 85 karma points
    May 24, 2021 @ 13:46
    Morten Peter Hagh Jensen
    0

    Thanks a lot, @Huw Reddick - Your answer pointed me in the right direction.

    I have created this

    public class MeetingDatesController : UmbracoApiController
        {
            // GET: MeetingDates
            [HttpGet]
            public Object MeetingDates(String theDate)
            {
                IPublishedContent content = Umbraco.Content(Guid.Parse("ff3e93f6-b34f-4664-a08b-d2eae2a0adbd"));
                var meettypes = content.Value<IEnumerable<IPublishedElement>>("meetingDatesAvailable");
    
                var items = new List<object>();
    
                foreach(var item in meettypes)
                {
                    if (item.Value("meetingItemDay").ToString().Substring(0, 8) == theDate) {
                        var times = item.Value<IEnumerable<IPublishedElement>>("meetingItemDayTimes");
    
                        foreach (var time in times)
                        {
                            items.Add(time.Value("meetingdateTimeItem").ToString());
                        }
                    }
                }
    
                return new { dateChosen = theDate, meetingTimes = items };           
            }
        }
    }
    

    Which actually works.

    Calling it with /umbraco/api/meetingdates/MeetingDates/?theDate=26-05-20ยด give me a response with

    {
        "dateChosen": "26-05-20",
        "meetingTimes": [
            "12:30",
            "15:30",
            "10:30"
        ]
    }
    

    which is what I wanted. Calling a date without any times gives an empty meetingTimes: []

    The code above can without a doubt be better! Any suggestions are greatly appreciated!

Please Sign in or register to post replies

Write your reply to:

Draft