I just need to know if it's correct hat I need to use the int[] option then?
The thing is I have created a custom picker that picks items from a custom database table. So I'm not quite sure if going down that path is correct.
When I render my data I get the array returned and in order to be able to select the data stored in the array I guess I should implement a property converter.
Just a quick question. Is this a picker for a single venue or multiple venues? Since your JSON model is an array, I would guess multiple venues, but from your example on how you'd like to use it, I would guess single venue picker. If you can shed some light on this, I can come up with an example ;)
If you change the model to an object rather than an array containing the object, it would be something like this. I haven't tested all of it, so throw something back at me if it doesn't work ;)
First the model (I haven't mapped all properties, but it should give you an idea on what going on):
public class BatJanVenue {
[JsonProperty("id")]
public int Id { get; private set; }
[JsonProperty("venue")]
public string Venue { get; private set; }
[JsonProperty("address")]
public string Address { get; private set; }
[JsonProperty("zip")]
public string Zip { get; private set; }
[JsonProperty("city")]
public string City { get; private set; }
[JsonProperty("country")]
public string Country { get; private set; }
public static BatJanVenue Deserialize(string json) {
// Validate the JSON
if (json == null || !json.StartsWith("{") || !json.EndsWith("}")) return null;
// Deserialize the JSON
return JsonConvert.DeserializeObject<BatJanVenue>(json);
}
}
The property value converter will then look like the code below. The trick here isn't the naming of the class, but specifying the correct PropertyEditorAlias:
public class BatJanVenuePropertyValueConverter : IPropertyValueConverter {
public bool IsConverter(PublishedPropertyType propertyType) {
return propertyType.PropertyEditorAlias == "NaNaNaNaNaNaNaNaNaNaNaNaBatJan";
}
public object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview) {
return source;
}
public object ConvertSourceToObject(PublishedPropertyType propertyType, object source, bool preview) {
return BatJanVenue.Deserialize(source as string);
}
public object ConvertSourceToXPath(PublishedPropertyType propertyType, object source, bool preview) {
return null;
}
}
How do decode this using the above method in umbraco 8. And where do I put in my controllers/models.
I wank to be able to access as
foreach (var H in Model.Heading)
{
var a = H.Heading;
var b = H.Tag;
}
so far I have put the above code below in a model.
I have an error comes up on this line
public class HeadingsPropertyValueConverter : IPublishedPropertyType
CS0535 'HeadingsPropertyValueConverter' does not implement interface member 'IPublishedPropertyType.Alias' ZekeCore D:\Web Development\Zeke Project\ZekeCore\Models\IBDAppPluginModelss.cs 55 Active
thin it repeats for .cashelevel, .clrtype, .contenttype, and so on
public class Headings
{
[JsonProperty("Heading")]
public string Heading { get; private set; }
[JsonProperty("Tag")]
public string Address { get; private set; }
public static Headings Deserialize(string json)
{
// Validate the JSON
if (json == null || !json.StartsWith("{") || !json.EndsWith("}")) return null;
// Deserialize the JSON
return JsonConvert.DeserializeObject<Headings>(json);
}
}
public class HeadingsPropertyValueConverter : IPublishedPropertyType
{
public bool IsConverter(PublishedPropertyType propertyType)
{
return propertyType.EditorAlias == "IBD.Headings";
}
public object ConvertDataToSource(PublishedPropertyType propertyType, object data, bool preview)
{
return Headings.Deserialize(data as string);
}
public object ConvertSourceToObject(PublishedPropertyType propertyType, object source, bool preview)
{
return source;
}
public object ConvertSourceToXPath(PublishedPropertyType propertyType, object source, bool preview)
{
return null;
}
}
While it matters little at the moment (it will in v8) you should probably deserialise in ConvertDataToSource, so that both Source and Object have the same value. e.g:
public class BatJanVenuePropertyValueConverter : IPropertyValueConverter {
public bool IsConverter(PublishedPropertyType propertyType) {
return propertyType.PropertyEditorAlias == "NaNaNaNaNaNaNaNaNaNaNaNaBatJan";
}
public object ConvertDataToSource(PublishedPropertyType propertyType, object data, bool preview) {
return BatJanVenue.Deserialize(data as string);
}
public object ConvertSourceToObject(PublishedPropertyType propertyType, object source, bool preview) {
return source;
}
public object ConvertSourceToXPath(PublishedPropertyType propertyType, object source, bool preview) {
return null;
}
}
@Anders I assume the jsonproperty stuff is just some attribute stuff that I need to add to my existing model, right? And what namespace do I need to reference? Getting the Error "The type or namespace name 'JsonPropertyAttribute' could not be found (are you missing a using directive or an assembly reference?)"
Being a C# novice...is there any easy way to figure out where to find the namespaces one needs? I find myself struggling with this from time to time in general. Is that what R# is good for?
I use a tool for Visual Studio called ReSharper, that helps with a lot of things - such as suggesting what namespaces to import when a class isn't found in one of the namespaces already imported. I think Visual Studio itself has a less intuitive way of doing something similar, but I cant remember how.
The IPropertyValueConverter interface is located in the Umbraco.Core.PropertyEditors namespace. When implementing the interface, you should also import the namespace Umbraco.Core.Models.PublishedContent.
The JsonProperty attribute is located in the Newtonsoft.Json namespace.
Thanks for the information - Yeah I know ReSharper (R#) but don't currently have it installed on my own machine. But it's installed on my machine at work...but rarely using Visual Studio :)
Thans for the information - I'll set it up now and see if I can succeed. Just had to change the property editor to store an object rather than the array.
Ok, got the build working - But now when trying to render the values using Razor I get: The type or namespace name 'BatJanVenue' could not be found (are you missing a using directive or an assembly reference?)
Description: An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately.
Compiler Error Message: CS0118: 'BatJan.Models' is a 'namespace' but is used like a 'type'
Source Error:
Line 34:
Line 35:
Line 36: public class PageViewsTournamentcshtml : BatJan.Models {
Line 37:
Line 38: #line hidden
Just a quick extra on a previous question around finding what namespaces you need - without R#, Ctrl and . is your friend (so hold down Ctrl and type the full stop character). It'll pop up then with the using statement you need. Doesn't work for extension methods unfortunately, but for most things that'll do it.
Thanks for chiming in - It's nice to know even though I try to avoid Visual Studio as much as I can - Afterall I'm a frontend developer preferring to work with Sublime text. But there is of course no way around it when doing stuff like this :)
If you're using anything other than Visual Studio, a tip for finding namespaces could be something like:
For Microsoft classes, I usually search for msdn+classname on Google, and Microsoft usually have a page for the class in their documentation showing what DLL/namespace the class is located in. This also works fine Visual Studio for when you haven't yet added a reference to the assembly the class is located in.
For Umbraco classes, you can head to https://github.com/umbraco/Umbraco-CMS and search for "class classname" or "interface interfacename". Usually the file for the class or interface is within the first few results.
Just one more question...I'm still a bit confused about this propertyValueConverter stuff. I have 2 other custom property editors that I need to convert as well.
However these are not based on data from a custom model like the first one was. However data from these are also stored as objects on $scope.model.value.
So I'm just thinking...do I need to create a custom model for those too? Or is it enough to just create the PropertyValueConverter class?
Since the property template property is defined as having the type object (even though it "behind the curtains" appears to be of the type JObject), the compiler doesn't know about its pos property.
There is a few ways to accomplish what you want:
If we choose to use your current model (the Competition class), you could do something like. Normally (and as you have experienced) the compiler will throw a YSOD if you trying to call a property it doesn't know about at compile time. Using the dynamic keyword turns this up side down, so you can call a property if it is there at runtime.
By using the dynamic keyword, we can take this even further. If you don't implement a property value converter for your property editor, Umbraco will automatically detect whether your model is either a JSON object (and return an instance of JObject) or a JSON array (and return an instance of JArray). If that is the case, your code could look as simple as:
You could compare this somewhat to calling properties in JavaScript.
The last is also the one that takes the most work. Your model could be updated to something similar to below.
In involves creating a new class to represent the template - eg.:
public class CompetitionTemplate {
[JsonProperty("pos")]
public int Position { get; private set; }
[JsonProperty("name")]
public string Name { get; private set; }
[JsonProperty("url")]
public string Url { get; private set; }
}
And updating the Competition class. I have only updated the template property since I don't know the structure of the other properties.
public class Competition {
[JsonProperty("template")]
public CompetitionTemplate template { get; private set; }
[JsonProperty("mixed")]
public object mixed { get; private set; }
[JsonProperty("seperate")]
public object seperate { get; private set; }
[JsonProperty("unisex")]
public object unisex { get; private set; }
[JsonProperty("doubles")]
public object doubles { get; private set; }
public static Competition Deserialize(string json)
{
// Validate the JSON
if (json == null || !json.StartsWith("{") || !json.EndsWith("}")) return null;
// Deserialize the JSON
return JsonConvert.DeserializeObject<Competition>(json);
}
}
Generally .NET/C# it is recommended to use upper camel casing for property names (eg. Template rather than template), but you are of course free to use what you think works best for you ;)
Ok, but do you advice using the dynamic approach? I'm tempted to just using this approach but I'm not sure about the consequences.
I think the other approach (3) seems like an awfull lot of work...I just chose to use "public object" since I don't know any better. In my thinking it's data saved as an object...bu should I have chosen differently?
Another question for the original property editor - When I create a new page and the venue has not been chosen I just save an empty object like $scope.model.value = {} - But that makes it pretty hard to test if there is any value when trying to render the template using Razor...so I tried to just save it as an empty string like $scope.model.value = '' but that gives me this error
Null object cannot be converted to a value type.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidCastException: Null object cannot be converted to a value type.
Source Error:
Line 108:
Line 109: // Deserialize the JSON
Line 110: return JsonConvert.DeserializeObject
So is there something that I need to take into account in my angular controller or in the venue model to allow it to be empty and make a check that the venue is only rendered if it's not empty?
Personally I would prefer the third approach, but that is because I Visual Studio, and it adds support for intellisense.
But if Visual Studio is only something you use under special circumstances, I would recommend using the second approach, and use dynamic all the way. This also means that you don't have to implement a property value converter ;)
Approach 3 is implementing what is called implementing a strongly typed model. I think most backenders would prefer it this way - I know I would. Normally using dynamic would take a little longer to execute than when not using it, but I don't know how much this is. The difference is probably insignificant.
For Umbraco, we can take the Grid as an example. Umbraco's on examples on how to render the Grid uses dynamic, but as a backender I would still prefer a strongly typed model - hence my GridData package.
If we assume the different in execution time is insignificant, I would recommend using a dynamic approach if you're not using Visual Studio or any other tool with intellisense, and you're working on this alone. If you're using Visual Studio, or one of your team members do (or you're releasing your property editor for the public), I would recommend going along with approach 3 and implement a strongly typed model.
Ok, thanks for your reply - It makes sense. I have been following the dynamics vs. strongly typed debate from a distance. Just wanted to make sure that it was the same thing in this context.
For now I'll go with using the dynamic approach and then perhaps refactor things at a later stage - This is a pet project of my own :)
I'm trying out on Approach 3 with the GridData package. Was wondering if you have example on your View and Controllers that you can share?
I have the Fanoe Grid Template installed to try it out and I'm trying to change the default Fanoe grid view (in Views/Partials/Grid/Fanoe.cshtml) to strongly type but are stuck with Base.cshtml (in Views/Partials/Grid/Editors/base.cshtml) where it's checking for the contentItem.Editor.Render but I can't seems to find the Render part in Skybrud
The Render property isn't part of the current release. The property is however in the most recent code on GitHub, so you could try that out.
I'm also working on wrapping up the next release, which will have this property as well as other improvements. Hopefully I'll have the time to release this later this week ;)
A question about property converters
Hi guys
I have build a property editor, which is saving an array to $scope.model.value - So in order to be able to fetch the values saved in the array I guess I need to make a property converter based on the documentation here https://github.com/umbraco/Umbraco4Docs/blob/master/Documentation/Extending-Umbraco/Property-Editors/value-converters-v7.md
I just need to know if it's correct hat I need to use the int[] option then?
The thing is I have created a custom picker that picks items from a custom database table. So I'm not quite sure if going down that path is correct.
When I render my data I get the array returned and in order to be able to select the data stored in the array I guess I should implement a property converter.
The data stored looks like this
And I would like to be able to fetch the content by writing something like
etc. So I guess I need to have a property converter setup so my Razor code would look something like this
Is that correct? And if so...what would my approach be?
Looking forward to receive some input.
Using 7.2.2 btw.
Cheers, Jan
Just a quick question. Is this a picker for a single venue or multiple venues? Since your JSON model is an array, I would guess multiple venues, but from your example on how you'd like to use it, I would guess single venue picker. If you can shed some light on this, I can come up with an example ;)
Hi Anders
It's actually just a single venue...so perhaps I should really just store it as an object rather than an object in an array :)
Looking forward to hearing your suggestions.
/Jan
Yup, then I would store it as a single JSON object. Example coming up for that ;)
If you change the model to an object rather than an array containing the object, it would be something like this. I haven't tested all of it, so throw something back at me if it doesn't work ;)
First the model (I haven't mapped all properties, but it should give you an idea on what going on):
The property value converter will then look like the code below. The trick here isn't the naming of the class, but specifying the correct
PropertyEditorAlias
:You would then use it like:
or:
Im using umbraco 8
I have created an plugin that returns a Jtoken.
The data is an array of values.
How do decode this using the above method in umbraco 8. And where do I put in my controllers/models.
I wank to be able to access as
so far I have put the above code below in a model.
I have an error comes up on this line
CS0535 'HeadingsPropertyValueConverter' does not implement interface member 'IPublishedPropertyType.Alias' ZekeCore D:\Web Development\Zeke Project\ZekeCore\Models\IBDAppPluginModelss.cs 55 Active
thin it repeats for .cashelevel, .clrtype, .contenttype, and so on
Haha! Thanks Anders, I love the "NaNaNaNaN..." part :D
Will have a look at it tomorrow afternoon and let you know if I can get it to work.
/Jan
While it matters little at the moment (it will in v8) you should probably deserialise in ConvertDataToSource, so that both Source and Object have the same value. e.g:
Hi guys
Thanks for your input - Having a look at it now.
@Anders I assume the jsonproperty stuff is just some attribute stuff that I need to add to my existing model, right? And what namespace do I need to reference? Getting the Error "The type or namespace name 'JsonPropertyAttribute' could not be found (are you missing a using directive or an assembly reference?)"
Being a C# novice...is there any easy way to figure out where to find the namespaces one needs? I find myself struggling with this from time to time in general. Is that what R# is good for?
Looking forward to hearing from you :)
Cheers, Jan
Sorry about the namespaces.
I use a tool for Visual Studio called ReSharper, that helps with a lot of things - such as suggesting what namespaces to import when a class isn't found in one of the namespaces already imported. I think Visual Studio itself has a less intuitive way of doing something similar, but I cant remember how.
The
IPropertyValueConverter
interface is located in theUmbraco.Core.PropertyEditors
namespace. When implementing the interface, you should also import the namespaceUmbraco.Core.Models.PublishedContent
.The
JsonProperty
attribute is located in theNewtonsoft.Json
namespace.Hi Anders
Thanks for the information - Yeah I know ReSharper (R#) but don't currently have it installed on my own machine. But it's installed on my machine at work...but rarely using Visual Studio :)
Thans for the information - I'll set it up now and see if I can succeed. Just had to change the property editor to store an object rather than the array.
I'll be back.
/Jan
Hi guys
Ok, so now I'm setting up the PropertyValueConverter but I'm stuck with 'BatJan.Models.BatJanVenue' does not contain a definition for 'Deserialize'
Anything else I need to do? Basically copy/pased the code Jeavon posted above and modified some naming.
/Jan
Could you post the two classes here?
Doh!
Forgot to add the serialize stuff to the model #h5is - Will imlement straight away :)
/Jan
Ok, got the build working - But now when trying to render the values using Razor I get: The type or namespace name 'BatJanVenue' could not be found (are you missing a using directive or an assembly reference?)
Do I need to inherit from my model?
/Jan
It depends on your current code. Most likely you would just need to import the
BatJan.Models
namespace.Hi Anders
Ok, but if I write this
I get this
Compilation Error
Description: An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately.
Compiler Error Message: CS0118: 'BatJan.Models' is a 'namespace' but is used like a 'type'
Source Error:
Line 34:
Line 35:
Line 36: public class PageViewsTournamentcshtml : BatJan.Models { Line 37:
Line 38: #line hidden
/Jan
Looks like you are attempting to inherit from BatJan.Models rather than import BatJan.Models. Try this just above your other inherit statement:
Hi Nicholas
Aah yes indeed I do! Being tired and coding is a bad cocktail :)
Now it works! Yay!
/Jan
Just a quick extra on a previous question around finding what namespaces you need - without R#, Ctrl and . is your friend (so hold down Ctrl and type the full stop character). It'll pop up then with the using statement you need. Doesn't work for extension methods unfortunately, but for most things that'll do it.
Andy
Hi Andy
Thanks for chiming in - It's nice to know even though I try to avoid Visual Studio as much as I can - Afterall I'm a frontend developer preferring to work with Sublime text. But there is of course no way around it when doing stuff like this :)
/Jan
If you're using anything other than Visual Studio, a tip for finding namespaces could be something like:
For Microsoft classes, I usually search for
msdn+classname
on Google, and Microsoft usually have a page for the class in their documentation showing what DLL/namespace the class is located in. This also works fine Visual Studio for when you haven't yet added a reference to the assembly the class is located in.For Umbraco classes, you can head to https://github.com/umbraco/Umbraco-CMS and search for
"class classname"
or"interface interfacename"
. Usually the file for the class or interface is within the first few results.Hi guys
Just one more question...I'm still a bit confused about this propertyValueConverter stuff. I have 2 other custom property editors that I need to convert as well.
However these are not based on data from a custom model like the first one was. However data from these are also stored as objects on $scope.model.value.
So I'm just thinking...do I need to create a custom model for those too? Or is it enough to just create the PropertyValueConverter class?
Hope that my question makes sense.
/Jan
Hello again
Ok, so I guess one will always need to create a model for custom property editors but that model does not need to reflect a database model.
But now I have kind of succesfully created a property value converter for another custom property editor.
This property editor saves multiple objects, which can then hold other objects as well.
So my code for the property value converter looks like this
PropertyEditorModel
public class Competition { [JsonProperty("template")] public object template { get; private set; }
}
And the value converter
public class CompetitionValueConverter : IPropertyValueConverter {
}
And it almost works...the thing is though that I have nested objects...so in my Razor code I can easily write stuff like
But this returns another object with data like this
And if I try writing
<p>@competition.template.pos</p>
for instance then i get a YSOD - So what do I need to allow for nested objects? :)/Jan
Hi Jan,
Since the property
template
property is defined as having the typeobject
(even though it "behind the curtains" appears to be of the typeJObject
), the compiler doesn't know about itspos
property.There is a few ways to accomplish what you want:
If we choose to use your current model (the
Competition
class), you could do something like. Normally (and as you have experienced) the compiler will throw a YSOD if you trying to call a property it doesn't know about at compile time. Using thedynamic
keyword turns this up side down, so you can call a property if it is there at runtime.By using the
dynamic
keyword, we can take this even further. If you don't implement a property value converter for your property editor, Umbraco will automatically detect whether your model is either a JSON object (and return an instance ofJObject
) or a JSON array (and return an instance ofJArray
). If that is the case, your code could look as simple as:You could compare this somewhat to calling properties in JavaScript.
The last is also the one that takes the most work. Your model could be updated to something similar to below.
In involves creating a new class to represent the template - eg.:
And updating the
Competition
class. I have only updated thetemplate
property since I don't know the structure of the other properties.Generally .NET/C# it is recommended to use upper camel casing for property names (eg.
Template
rather thantemplate
), but you are of course free to use what you think works best for you ;)Hi Anders
Ok, but do you advice using the dynamic approach? I'm tempted to just using this approach but I'm not sure about the consequences.
I think the other approach (3) seems like an awfull lot of work...I just chose to use "public object" since I don't know any better. In my thinking it's data saved as an object...bu should I have chosen differently?
Another question for the original property editor - When I create a new page and the venue has not been chosen I just save an empty object like $scope.model.value = {} - But that makes it pretty hard to test if there is any value when trying to render the template using Razor...so I tried to just save it as an empty string like $scope.model.value = '' but that gives me this error
Null object cannot be converted to a value type. Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidCastException: Null object cannot be converted to a value type. Source Error: Line 108: Line 109: // Deserialize the JSON Line 110: return JsonConvert.DeserializeObject
So is there something that I need to take into account in my angular controller or in the venue model to allow it to be empty and make a check that the venue is only rendered if it's not empty?
/Jan
Personally I would prefer the third approach, but that is because I Visual Studio, and it adds support for intellisense.
But if Visual Studio is only something you use under special circumstances, I would recommend using the second approach, and use dynamic all the way. This also means that you don't have to implement a property value converter ;)
Hi Anders
Aaah...:) - But what is the best practice? Is'nt "dynamics" what all the backend devs hate? Or is that something else? :)
/Jan
I'm not totally sure what the best practice is.
Approach 3 is implementing what is called implementing a strongly typed model. I think most backenders would prefer it this way - I know I would. Normally using dynamic would take a little longer to execute than when not using it, but I don't know how much this is. The difference is probably insignificant.
For Umbraco, we can take the Grid as an example. Umbraco's on examples on how to render the Grid uses dynamic, but as a backender I would still prefer a strongly typed model - hence my GridData package.
If we assume the different in execution time is insignificant, I would recommend using a dynamic approach if you're not using Visual Studio or any other tool with intellisense, and you're working on this alone. If you're using Visual Studio, or one of your team members do (or you're releasing your property editor for the public), I would recommend going along with approach 3 and implement a strongly typed model.
Hi Anders
Ok, thanks for your reply - It makes sense. I have been following the dynamics vs. strongly typed debate from a distance. Just wanted to make sure that it was the same thing in this context.
For now I'll go with using the dynamic approach and then perhaps refactor things at a later stage - This is a pet project of my own :)
Thanks for helping me out.
/Jan
Hi Anders,
I'm trying out on Approach 3 with the GridData package. Was wondering if you have example on your View and Controllers that you can share?
I have the Fanoe Grid Template installed to try it out and I'm trying to change the default Fanoe grid view (in Views/Partials/Grid/Fanoe.cshtml) to strongly type but are stuck with Base.cshtml (in Views/Partials/Grid/Editors/base.cshtml) where it's checking for the contentItem.Editor.Render but I can't seems to find the Render part in Skybrud
Hi Jeric,
The
Render
property isn't part of the current release. The property is however in the most recent code on GitHub, so you could try that out.I'm also working on wrapping up the next release, which will have this property as well as other improvements. Hopefully I'll have the time to release this later this week ;)
Thanks Anders,
Looking forward for the next release :)
For time being I'll grab them from GitHub.
Thanks a lot
Hi again,
I have now set up a new repository with partial views for rendering the Grid. You can find it here: https://github.com/abjerner/Skybrud.Umbraco.GridData.PartialViews
It is just an example, and still a bit work in progress. You hopefully it helps you continue on your own ;)
is working on a reply...