Copied to clipboard

Flag this post as spam?

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


  • Devin Bost 37 posts 78 karma points c-trib
    Nov 12, 2014 @ 18:31
    Devin Bost
    0

    How to undestroy the custom data type via ContentService?

    Hi,

    I implemented a custom data type to provide the results of a calculation that needs to be frequently updated. The service works fine from the management interface, and the value is displayed properly... However, when I try to obtain the value from the API via ContentService, the property value was returning null. Initially, I assumed that I was trying to retrieve the value before the node was constructed; so I tried setting an initial value in the property for the interim (so I would have something to return). What is confusing, however, is that now the property value that I set is the only value displayed when I query the objects. In other words, by setting the property value manually I completely demolished the functionality of the custom data type. This breaks the custom data type in the backend.

    Here are the parts of the package:

    <div ng-controller="ComputeAttendeeTotalTimeController">
        <h4>{{totalTime.data}}</h4>
    </div>
    

    Next:

    angular.module("umbraco").controller("ComputeAttendeeTotalTimeController", function($scope, totalTimeResource, $routeParams){
        $scope.nodeId = $routeParams.id;
        $scope.totalTime = totalTimeResource.GetAttendeeTotalTime($scope.nodeId);
    
    });
    

    Next:

    angular.module("umbraco.resources").factory("totalTimeResource", function($http){
        var myService = {};
        myService.GetAttendeeTotalTime = function(nodeId){
            return $http.get("/api/Content/GetAttendeeTotalTime?nodeId=" + nodeId);
        };
        return myService;
    });
    

    The API controller method is way more complicated than it should be, but here it is:

        [HttpGet]
        [Route("GetAttendeeTotalTime")]
        [ActionName("GetAttendeeTotalTime")]
        public string GetAttendeeTotalTime([FromUri] string nodeId)
        {
            var nodeIdInt = int.Parse(nodeId);
            Models.Content attendeeNode = this.contentFactory.GetSingleContent(nodeIdInt, true);
            var roundedMin = ComputeAttendedTime(attendeeNode);
    
            return roundedMin.ToString(CultureInfo.InvariantCulture);
        }
    
        private double ComputeAttendedTime(fyinModels.Content attendeeNode)
        {
            var attendedDateTime = attendeeNode.Properties.FirstOrDefault(prop => prop.Key == "attendedDateTime");
    
            DateTime convertedAttendedDateTime;
            if (attendedDateTime.Value == null)
            {
                convertedAttendedDateTime = DateTime.Now;
                // throw new NullReferenceException("attendedDateTime cannot be null");
            }
            else
            {
                var attendedTimeStr = attendedDateTime.Value.ToString();
                convertedAttendedDateTime = DateTime.Parse(attendedTimeStr);
            }
    
    
            var parentNode = attendeeNode.Source.Parent();
            var parentNodeModel = this.contentFactory.GetSingleContent(parentNode.Id);
            var parentClosedTime = parentNodeModel.Properties.FirstOrDefault(prop => prop.Key == "closedDateTime");
            DateTime parentClosed;
            if (parentClosedTime.Value == null || String.IsNullOrEmpty(parentClosedTime.Value.ToString()))
            {
                // if not closed, use system time. Else, use closed time.
                parentClosed = DateTime.Now;
            }
            else
            {
                var closedTime = parentClosedTime.Value.ToString();
                parentClosed = DateTime.Parse(closedTime);
            }
            var difference = parentClosed - convertedAttendedDateTime;
            // Now that we have computed the difference, we need to determine how much time has passed between the
            // time attended and now.
            var sinceNow = DateTime.Now - convertedAttendedDateTime;
            if (sinceNow.Minutes < 0)
            {
                throw new ArgumentOutOfRangeException("Minutes should not be negative.");
            }
    
    
            var minutes = difference.TotalMinutes + sinceNow.TotalMinutes;
            // serialize difference
            var roundedMin = Math.Round(value: minutes, digits: 0);
            return roundedMin;
        }
    }
    

    Can someone please explain how to retrieve the computed value from the custom data type?

  • Charles Afford 1163 posts 1709 karma points
    Nov 13, 2014 @ 23:15
    Charles Afford
    0

    Have you debugged your controller. Everything above the controller looks fine and you are using $scope which is good :). Charlie

  • Andy Butland 422 posts 2334 karma points MVP 4x hq c-trib
    Nov 15, 2014 @ 20:41
    Andy Butland
    0

    I wonder if it's something around your call to $http.get in your totalTimeResource?  You are returning the result directly rather than using the success callback.

    See here for documentation on angular's $http.get.

    I'm not sufficiently expert in angular to give a definitive answer but basically as I understand you are getting the promise back to your controller and not the retrieved value.  Instead I think you need to look at something like this, to resolve the promise in your controller:

    totalTimeResource.GetAttendeeTotalTime($scope.nodeId).then(function(data) {
        $scope.totalTime = data;
    });
    

    Hope that's of use.

    Andy

  • Devin Bost 37 posts 78 karma points c-trib
    Dec 10, 2014 @ 14:55
    Devin Bost
    0

    I have updated the code, but I am still getting the same issue. See the pictures below for the proof. It is fascinating. In the Google dev group, there was a suggestion to use a custom resolver, but I haven't been able to find much information about how to tap into that.

    Here's the updated controller:

    angular.module("umbraco").controller("ComputeAttendeeTotalTimeController", function($scope, totalTimeResource, $routeParams){
        $scope.nodeId = $routeParams.id;
        totalTimeResource.GetAttendeeTotalTime($routeParams.id).then(function (response) {
            $scope.totalTime = response.data;
        });
        //$scope.totalTime = totalTimeResource.GetAttendeeTotalTime($scope.nodeId);
        // get current time and compute difference.
    });
    

    And the service:

    angular.module("umbraco.resources").factory("totalTimeResource", function ($q, $http) {
        return {
            //this cals the Api Controller we setup earlier
            GetAttendeeTotalTime: function (nodeId) {
                return $http.get("/api/Content/GetAttendeeTotalTime?nodeId=" + nodeId);
            }
        };
    });
    

    And the manifest:

    {   
        propertyEditors: [      
            {
                alias: ".ComputeAttendeeTotalTime",
                name: "Compute Attendee Total Time",
                editor: {
                    view: "/App_Plugins/ComputeAttendeeTotalTime/ComputeAttendeeTotalTime.editor.html",
                    valueType: "JSON"
                },
                defaultConfig: {
                },
                prevalues: {
                    fields: [
                    ]
                }
            }
        ],
        javascript: [
            '/App_Plugins/ComputeAttendeeTotalTime/ComputeAttendeeTotalTime.editorcontroller.js',
            '/App_Plugins/ComputeAttendeeTotalTime/ComputeAttendeeTotalTime.resource.js'
        ],
        css: [
        ]
    }
    

    And the view:

    <div ng-controller="ComputeAttendeeTotalTimeController">
        <h4>{{totalTime.data}}</h4>
    </div>
    

    And the API controller method:

        [HttpGet]
        [Route("GetAttendeeTotalTime")]
        [ActionName("GetAttendeeTotalTime")]
        public int GetAttendeeTotalTime([FromUri] string nodeId)
        {
            var nodeIdInt = int.Parse(nodeId);
            Models.Content attendeeNode = this.contentFactory.GetSingleContent(nodeIdInt, true);
            var attendedDateTime = attendeeNode.Properties.FirstOrDefault(prop => prop.Key == "attendedDateTime");
            if (attendedDateTime.Value == null)
            {
                throw new NullReferenceException("attendedDateTime cannot be null");
            }
            var attendedTimeStr = attendedDateTime.Value.ToString();
            var convertedAttendedDateTime = DateTime.Parse(attendedTimeStr);
            //DateTime currentDate = DateTime.UtcNow; // For some reason, the backend storage is not UTC.
            DateTime currentDate = DateTime.Now;
            TimeSpan span = currentDate - convertedAttendedDateTime;
            var roundedSpan = Convert.ToInt32(Math.Round(span.TotalMinutes));
    
            return roundedSpan;
        }
    

    We can see that the property is null from the API controller:

    Image of property not appearing from API controller in Visual Studio

    But interestingly, the property is clearly there in the management interface:

    Image of Umbraco property editor plugin value (from custom data type) appearing properly

    Do we have any ideas regarding how to access this value from the API controller? If anyone has an idea of how to create a custom resolver, that would be much appreciated.

    -Devin

Please Sign in or register to post replies

Write your reply to:

Draft