Annotation for Json Model in ASP.Net MVC - json

I'm working on an ASP.Net MVC2 application and use the jsTree-Komponent for jQuery to render a tree with checkboxes.
To select specific nodes in a convenient way my JSON has to offer a "class" attribute.
Here's an example how jsTree wants to consume the JSON result:
[{"data":"Root1","attr":{"id":"10","class" : "jstree-checked"} ...
In the controller I use "return Json(tree);" to create the Json and my ViewModel would than need a "class" property. A "class" property isn't allowed in C# as it is a reserved word.
Is there a way to Annotate the ViewModel's attribute as it is with XML?
XMLExample:
[XmlAttribute("class")]
public string cssClass = "";
Or are there other suggestions to handle this on the server side?
Cheers,
Helmut

I finally solved this and answer the question on my own.
If my description on the topic had been clearer, someone would have probably answered this question a long time ago.
Instead of using the property "class" (which is a reserved key word) you can specify "#class".
Here's a small code snippet that works.
var tree = new JsTreeModel[]
{
new JsTreeModel {
data = new JsTreeData{title="Root1"},
attr = new JsTreeAttribute { id="10",#class="jstree-checked" }
}
}
I have used the #class attribute in different scenarios (e. g. for specifying a css-class in Html.Actionlink) but haven't transfered that knowledge to the JSON example...

Related

Add components based on string variables in Blazor

We're creating a dynamic page of components in Blazor. The intention is to have dynamic applets displayed on a page. The idea is that we have a list of strings which correspond to Component names. We read through the string list and for each one, instantiate a blazor component or render fragment. These are just simple components, no passed in parameters or the like. ie:
string[] componentsStrings = {"Component1", "Component2"};
Expected output:
<Component1 />
<Component2 />
We can't come up with a way to do this. It seems like a fairly standard thing to do, but perhaps not? Does anyone know if this is even possible?
You will have to programmatically create a component which adds your custom components on the page using RenderTreeBuilder.
Chris Sainty has a blog post on this which you can read here: https://chrissainty.com/building-components-via-rendertreebuilder/
Basically there is an override for BuildRenderTree in the ComponentBase class which can be used:
public class Menu : ComponentBase
{
protected override void BuildRenderTree(RenderTreeBuilder builder)
{
base.BuildRenderTree(builder);
builder.OpenElement(0, "nav");
builder.AddAttribute(1, "class", "menu");
}
}
Here is another tutorial.
Some tips from here:
Place base.BuildRenderTree(builder); at the start of the
BuildRenderTree method , not at the end.
Always start with the value 0 for the sequence parameter.

Render different partial templates in EpiServer

I have a page partial that is supposed to render inside a ContentArea when the page is added there. This works perfectly, but now I have two different ContentAreas on two different pages and I want the same child page added to those to render different on each parent page.
I get that I could in some way use a Tag when rendering the partial to differentiate between the ContentAreas:
#Html.PropertyFor(m => m.MyBlockProperty, new { Tag = RenderingTags.Sidebar })
#Html.PropertyFor(m => m.MyContentArea, new { Tag = RenderingTags.Sidebar })
But then, in my SomePage.cshtml (which is my partial view), do I get a varaible or something here so I know which Tag was asked for? Or is there some naming convention like SidebarSomePage.cshtml so that I can define multiple partial templates? Do I have to create a controller to deal with this? It seems unneccessary to me, I just want to change the html a bit depending on page...
Create a PartialContentController<T> and then use the TemplateDescriptorAttribute to specify the tags you wan't to use. Then use PropertyFor as Johan explained in the view.
From the EPiServer documentation
The template you choose to render a content instance depends on the specific context such as channel and tagging. For a template to be automatically registered it has to implement EPiServer.Web.IRenderTemplate (where T states which model it can render). If you use a base class for your template like PageBase, ContentControlBase, BlockControlBase, PageController, PartialContentController or BlockController, then you do not need to explicitly implement the interface because that is done by the base class. In addition, you can use the TemplateDescriptorAttribute to specify more details about the template such as tags and inheritance, more information on that topic later.
I'm pretty sure you can access the tag from the ViewData dictionary in your view (or controller) like this:
#ViewData["Tag"]
You can also pass any other setting to the view
#Html.PropertyFor(m => m.MyContentArea, new { Tag = RenderingTags.Sidebar, RenderThisPartialDifferently = true, ShowHeading = false })
And then access them:
#ViewData["RenderThisPartialDifferently"]
#ViewData["ShowHeading "]
And then you have the option to have a controller in between and render a completely different view.
Pretty sure there is a naming convention for tag views as well. What I do know for sure though, is that you can put a view with the same name as the tag in /shared/displaytemplates. But that's not what you're asking for now.
Also addition to all answers, you can use template registrator to register additional templates for specific tags.
[ServiceConfiguration(typeof(IViewTemplateModelRegistrator))]
public class TemplateCoordinator : IViewTemplateModelRegistrator
{
public void Register(TemplateModelCollection viewTemplateModelRegistrator)
{
viewTemplateModelRegistrator.Add(typeof(MyBlock), new TemplateModel
{
Tags = new[] { RenderingTags.Sidebar },
AvailableWithoutTag = false,
Path = BlockPath("Some-Other-Template.cshtml")
});
}
}
This will make sure that if block is rendered "inside" RenderingTags.Sidebar context (for instance via Html.PropertyFor(...., new { tag = RenderingTags.Sidebar })) file Some-Other-Template.cshtml will be used.
AlloyTech has sample code there.

How to mock a CQ5 Page object containing a cq5 tag

I have a method on which I'd like to run a JUnit test. I'm mocking the cq5 page using JMockit.
My test method looks like this
#Mocked
Page page;
#Mocked
PageManager pageManager;
Tag testTag = pageManager.createTag("someID","someTitle","someDescription");//i've left out the try catch for brevety
System.out.println(testTag.getTitle()); // always null here
public void testSomeMethod() {
new Expectations() {
// variables declared here are mocked by default
{
page.getProperties();
propertyMap.put("cq:tags", testTag);
returns(new ValueMapDecorator(propertyMap));
}
};
String propertyValue = methodToBeTested(page);
Assert.assertEquals(propertyValue, "someTitle");
}
And the actual method to be tested does this :-
public static String getTopic(Page page) {
String topic = null;
Tag[] tags = page.getTags();
System.out.println(tags.size()); // returns 0 when I run the test.
for (int i = 0; i < tags.length; i++) {
Tag tag = tags[i];
topic = tag.getTitle();
}
}
return topic;
}
This always returns null when I run the test; however the method to be tested works correctly in the real scenario.
I suspect I'm not setting/mocking PageManager correctly, and consequently, my testTag is null
How do I mock this correctly to get the output I'm looking for?
You're getting to this testing from the wrong side. The way mocks (usually - I've never worked with jmockit specifically) work is, you create a blank object that acts as an impostor. This impostor is not a true PageManager - it only acts as one, and introduces himself as one whenever asked. When someone asks that impostor to do something (like calling it's method), the impostor does not know what to do, so it does nothing and returns null. However, you can tell the impostor how to behave in certain situations. Namely, you can tell it what to do when a method is called.
In your case, you don't need to create actual tags to test that method - you only need to mock a page object that, when asked for it's tags, will return an array containing a mocked tag which, in turn, when asked for it's title, will respond with the title you actually want to use in your test.
I don't know jmockit, so I cannot provide any code snippet. This, however, is a general question not strictly connected to CQ5/AEM
You may not be able to find any 'setter' methods for all objects you are trying to mock and this is anyways not the correct approach to mock.
The best way as mentioned by is to use mocked pages. You can use the Expectations class (mockit.Expectations) to mock the values to be returned by certain methods in the object.
See this example of mocking a 'SlingHttpServletRequest' object in a MockedClass class.
#Test
public void testMethod(#Mocked final SlingHttpServletRequest request){
String indicator ;
new Expectations() {
{
request.getParameter("archive");
returns("true");
}
};
indicator = OriginalClass.originalMethod(request);
Assert.assertEquals(indicator, "true");
}
In a similar way, you can mock other objects and their desired values.
I have answered the same question here: https://forums.adobe.com/thread/2536290
I ran into the same issue. in order to resolve Tags, they must exists under /content/cq:tags/your/tag or /etc/tags (legacy).
The Page#getTags implementation makes a call to TagManager#getTags which in turn tries to resolve the actual tag resource in the repo. Since you are testing in an AEM context, you have to load these tags in the appropriate location for the MockTagManager to resolve them.
What this means is that you need to load your tags into the AEM test context just like you've loaded your resources (via json).
Take a look at the aem-mock TagManager impl here: wcm-io-testing/MockTagManager.java at develop · wcm-io/wcm-io-testing · GitHub start with the resolve method and debug your way to figure out where you need to add those tags.

How to use contents = to add to a Scala Panel?

Sorry this must be a very silly question.. but everywhere I've been seeing Scala code examples where you just do
contents+= on a BoxPanel or some layout Panel. I figured because they have contents as mutable.buffer so you can just add and remove components.
But how do you add a component to Scala Panel? It accepts a seq so do you have to give it a list or something? I know you can just call peer.add but I want to see how Scala code does it. :)
For example contents = new Button {} isn't working.
Sorry for this simple question I'm very new to Scala..
EDIT:
Thanks for the replies. My question now though becomes.. can you ever just have a class extending Panel? Would you be able to set contents for it at all? Or is it never done and everyone always just uses the Panels associated with a layout manager?
The Panel class itself is abstract, meaning it can't be instantiated directly, and is intended as a "base" for concrete implementations of panels.
It doesn't seem to have a "common" method for adding components probably because each subclass implements its own, sometimes mutually incompatible custom one:
BoxPanel, as you've noted, has a settable Buffer,
FlowPanel seems to mandate adding components as constructor arguments,
GridBagLayout and some others implement addition via the layout Map,
etc.
As you might see from the above examples, it would be hard to specify what a general "add" method would mean in all of those cases.
EDIT in response: of course you can, there's nothing stopping you from subclassing a Panel yourself and override the contents method, e.g.:
val myPanel = new Panel() {
private val myContents = (new Content += new Button())
override def contents = myContents
}
You can also use Panel as a type parameter for your methods that process panels in a general way, etc. It's just that you can't have an instance that's just a Panel, because, again, the class is abstract, so you can't instantiate it.
Note that this is not unique to Scala, if JPanel was abstract in Java (like Component is) the outcome would be the same.
I want to see how Scala code does it.
https://github.com/scala/scala-swing/blob/v1.0.0-RC2/src/main/scala/scala/swing/Container.scala#L35
I, too, practiced on some Swing code when I first learned some Scala.
Here is a Panel component that renders itself as a simple game grid:
https://github.com/som-snytt/House-of-Mirrors-Fork/blob/act/src/main/scala/hom/LightBox.scala#L286
To see how the Scala and Swing pieces fit together, see SuperMixin:
https://github.com/scala/scala-swing/blob/v1.0.0-RC2/src/main/scala/scala/swing/Component.scala#L51
Assembly:
https://github.com/som-snytt/House-of-Mirrors-Fork/blob/act/src/main/scala/hom/HouseOfMirrors.scala#L18
This is what you asked about directly:
https://github.com/som-snytt/House-of-Mirrors-Fork/blob/act/src/main/scala/hom/HouseOfMirrors.scala#L45
If you have a button:
val button=new Button{
text="Click me!"
}
or
val label=new Label{
text="Look, i'm a label!"
}
or
object myField extends TextField{ columns=2 }
then you just use:
contents=new BoxPanel(Orientation.Vertical){
contents+=button
border=Swing.EmptyBorder(10,20,10,20)
}
or in a more simpler form:
contents=new FlowPanel(){
contents+=new Label("This is my button:")
contents+=new Button("Click me!")
border=Swing.EmptyBorder(10,20,10,20)
}

umbraco razor - getting fields from content

I have a 6 items of the same content type "news", in each item I have a field newsIntro. I want to put the fields in specific pages on another page so I need to target a specific field so it may be newsIntro on node 1702. I have tried a few things like
#1720.newsIntro
how do I target a specific field
Thanks
There are some great resources you should take a look at while you are learning Razor:
Umbraco Razor Feature Walkthrough - An eight part blog post series of many of the new Razor features in Umbraco 4.7 with examples.
Razor DynamicNode Cheat Sheet - A PDF of all the properties and methods available to the Razor DynamicNode object (that includes #Model).
Cultiv Razor Examples - An Umbraco website that you can download and open with WebMatrix or IIS and see various ways to access properties with Razor.
Razor snippets - A compilation of different snippets, examples, etc. from Our Umbraco.
But in answer to your question, to get a property of a specific node you have to get the actual DynamicNode object first, then use the property alias to access the property value. Example:
#{
//Get the node
dynamic node = Library.NodeById(1720);
// Display the property
#node.newsIntro
}
To access a property from the current page, you simply use Model:
#Model.newsIntro
or
#Model.bodyText
or
#Model.Name
First, get an IPublishedContent object from the TypedContent method and then use GetPropertyValue to retrieve the value of the field.
#{
int nodeId = 1720;
IPublishedContent contentNode = Umbraco.TypedContent(nodeId);
var newsIntro = contentNode.GetPropertyValue("newsIntro");
}
<p>#newsIntro</p>
With Umbraco 7 I used this code to get property from different pages:
#Umbraco.Content(1720).newsIntro
If the content item 1720 is a parent or ancestor of the page where you want to use the value, you can get it recursively like this:
#Umbraco.Field("newsIntro", recursive: true)
To get fields from content I have used this:
#{
var selection = Umbraco.TypedContent(contentId).Children()
.Where(x => x.IsVisible())
.OrderBy("CreateDate");
}
#foreach(var item in selection){
#item.GetPropertyValue("fieldName1")
#item.GetPropertyValue("fieldName2")
#item.GetPropertyValue("fieldName_N")
}