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.
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?
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:
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);
}
};
});
[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:
But interestingly, the property is clearly there in the management interface:
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.
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:
Next:
Next:
The API controller method is way more complicated than it should be, but here it is:
Can someone please explain how to retrieve the computed value from the custom data type?
Have you debugged your controller. Everything above the controller looks fine and you are using $scope which is good :). Charlie
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:
Hope that's of use.
Andy
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:
And the service:
And the manifest:
And the view:
And the API controller method:
We can see that the property is null from the API controller:
But interestingly, the property is clearly there in the management interface:
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
is working on a reply...