How to get values returned by child action method in mvc 5 partial view - asp.net-mvc-5

I am trying not very successfully to get my head around MVC. My home controller contains an Index method that runs OK, so far so good, but I don't know how to call the ChildAction method Home/TopArticle
Action Method
[ChildActionOnly]
public ActionResult TopArticle()
{
return PartialView(_service.GetTopArticle());
}
In my Index view I have the mark up:
#section featured {
#Html.Partial("_TopItem")
}
_TopItem View
#model IEnumerable<MySite.Models.NewPage>
<section class="featured">
<div id="TopItem">
<div id="TopItemImg">
<a href="http://www.mysite.co.uk/">
<img style="border: 1px solid lightgray" width="320" height="233" style="border:1px solid lightgray;" alt="Model.Title" src="/Img/Model.TopItemImage">
</a>
</div>
<div id="TopContent">
<h2></h2>
<div class="dt">
<div class="dl">
#Html.Label(Model.DatePublished.ToString())
#Html.Label(#Html.Action("TopArticle", "Home", new { // am lost at this point}))
</div>
<div class="tl">
#Html.Label(Model.InfoTags ?? "")
</div>
</div>
</div>
</div>
</section>
The Index view is also using #model IEnumerable and I don't actually know whether that's OK or not. The model itself contains everything needed for both the Index and the _TopItem views, it's just that there will be one record returned for the _TopItem view and many for the Index view. Plus the code that runs in _service.GetTopArticle does some non-query stuff that is relevant only for the top article record.
I need a lie down ... and time to learn this stuff properly.

Firstly, regarding your question about calling the child action from your Index view:
Your featured section is currently calling #Html.Partial which means that it will find the "_TopItem" partial view and render it as an html encoded string in the current view (i.e. your Index view).
You specified that you are trying to call the child action TopArticle() and render the partial view returned as a html string in the view. To do this you would need to use:
#section featured {
#Html.Action("TopArticle", "Home")
}
However, I don't believe this is what you do need as you said that your Index view model contains all of the information for both Index and for the _TopItem partial view (see later).
For more information you should do a google search about the differences of views, partial views and child actions.
To correct the code I would start off by ensuring that the _TopItem partial view is correct. I have identified the following issues with the _TopItem partial view, some of which are beyond the scope of the original question:
The model passed in as an IEnumerable of NewPage but your code does not enumerate over several new page objects, it looks like it should just create the html for a single NewPage model. Therefore, I believe the model declaration should be:
#model MySite.Models.NewPage
The tag contains 2 references to the style attribute rather than 1.
The tag contains the alt attribute of alt="Model.Title" which means that alt="Model.Title" will be written directly as html where I expect you would like alt="#Model.Title" to render the contents of the model in the alt attribute.
Similarily, the tag contains src="/Img/Model.TopItemImage" where I expect this should be src="/Img/#Model.TopItemImage"
All of the label tags appear to be incorrect. For example, #Html.Label(Model.DatePublished.ToString()) - Model.DatePublished.ToString() will return a string and this string will then be attempted to be found on the model and will error as that field name does not exist. Therefore, you probably want to write: #Html.Label("DatePublished") or #Html.Label(m => m.DatePublished). With the second label i'm not sure what your trying to achieve but you may want to look up the appropriate articles.
Once, you have the corrected _TopActicle partial view, you can then return to your Index view to render the partial directly:
#section featured {
#Html.Partial("_TopItem", Model.TopArticle)
}
Note, as you have said that your Index model contains the information to pass to the _TopItem partial view, I have assumed that the Index model contains a property called TopArticle of type NewPage. Regardless, you can pass the model into the partial however you find appropriate through the call to #Html.Partial. If you pass the model through the call to #Html.Partial then you may not need the ChildOnlyAction.

Related

Render JSF h:message with p element instead of span

I would like to create a custom message renderer to renders h:message as a 'p' html element instead of as a 'span' element. It concerns the following message tag:
<h:message id="firstNameErrorMsg" for="firstname" class="error-msg" />
I've written to code underneath, but that's only rendering an empty 'p' element. I suppose I have to copy all attributes and text from the original component and write it to the writer. However, I don't know where to find everything and it seems to be a lot of work for just a replacement of a tag.
Is there a better way to get an h:message tag rendered as a 'p' element?
Code:
#FacesRenderer(componentFamily = "javax.faces.Message", rendererType = "javax.faces.Message")
public class FoutmeldingRenderer extends Renderer {
#Override
public void encodeEnd(final FacesContext context, final UIComponent component) throws IOException {
ResponseWriter writer = context.getResponseWriter();
writer.startElement("p", component);
writer.endElement("p");
}
}
It isn't exactly "a lot of work". It's basically a matter of extending from the standard JSF messages renderer, copypasting its encodeEnd() method consisting about 200 lines then editing only 2 lines to replace "span" by "p". It's doable in less than a minute.
But yes, I agree that this is a plain ugly approach.
You can consider the following alternatives which are not necessarily more easy, but at least more clean:
First of all, what's the semantic value of using a <p> instead of a <span> in this specific case? To be honest, I'm not seeing any semantic value for this. So, I suggest to just keep it a <span>. If the sole functional requirement is to let it appear like a <p>, then just throw in some CSS. E.g.
.error-msg {
display: block;
margin: 1em 0;
}
You can obtain all messages for a particular client ID directly in EL as follows, assuming that the parent form has the ID formId:
#{facesContext.getMessageList('formId:firstName')}
So, to print the summary and detail of the first message, just do:
<c:set var="message" value="#{facesContext.getMessageList('formId:firstName')[0]}" />
<p title="#{message.detail}">#{message.summary}</p>
You can always hide it away into a custom tag file like so:
<my:message id="firstNameErrorMsg" for="firstname" class="error-msg" />
Use OmniFaces <o:messages>. When the var attribute is specified, then you can use it like an <ui:repeat>.
<o:messages for="firstNameErrorMsg" var="message">
<p title="#{message.detail}">#{message.summary}</p>
</o:messages>

Showing properties from another table - Kentico

we just started with Kentico and are now testing a bit. One thing we're stuck on is showing data in transformations.
We have a custom table like Author. It hase a ID field, FirstName and SurName (both text).
Book is a documenttype and has an ID, Title and a dropdown where we can select an Author.
On a page a have a datalist where i show book with a previewtransformation like this:
<div style="text-align:center;padding: 8px;margin: 4px;border: 1px solid #CCCCCC">
<h2>
<%# Eval("Title") %>
</h2>
Author: <%# Eval("Author.FirstName") %>
</div>
Now we want to show the name of the Author but when using <%# Eval("Author") %> it's showing the ID. We found out that we can use a custom function and return the name, but isn't there another way? Let's say we not only want to show the author's name, but also address, email and so on... Do we really need to create an method for each property we want to show?
Thanks in advance,
Bjorn
No, you can't drill into related tables in this way, because the data of an author is simply not in the data source you are displaying with the data list.
But you don't have to create function for each property of an author you want to display. You may just create a function which will return whole author object, which is in your case CustomTableItem. The function may look like this.
public CustomTableItem GetAuthor(object id)
{
int authorId = ValidationHelper.GetInteger(id, 0);
var pr = new CustomTableItemProvider();
var item = pr.GetItem(authorId, "customtable.author");
return item;
}
Then in a transformation you will use GetValue() method to get the value.
Author: <%# GetAuthor(Eval("AuthorID").GetValue("FirstName")) %>
Be aware of each call of the function will issue a database request, so i would suggest to use some kind of caching. Either output cache for whole page or you may implement some caching mechanism directly inside the function.
The other option you also have is to use CustomQueryRepeater/DataSource and write your own SQL query where you join book data with author data. Then you could use simply <%# Eval("FirstName") %> directly in yout transformation.

Orchard Alternate Shape Template Not Displaying Values

I'm new to Orchard and have watched both the Pluralsight "Orchard Fundamentals" and "Advanced Orchard" tutorials. Its a great platform, but I'm having a hard time wrapping my head around a couple of things.
I'd like to create a blog showcase banner on the home page only that rotates blog posts on the site. I have the HTML sliced up and functioning on an HTML template. The banner looks like this:
http://arerra.com/news-slideshow.jpg
So far I have done the following:
I've created a Blog called "Articles" and have placed a single post in there for testing.
Added a Layer called "ArticleList" where I have placed a Widget for "Recent Blog Posts"
I've created a custom layout for the home page called "Layout-Url-HomePage.cshtml" in my theme.
In my Theme "Views" folder, I have created a file called "Widget.Wrapper.cshtml" with only #Display(Model.Child) in it to remove the <article><header/><footer /><article> tags globally from the widgets.
Added a file in "Views > Parts > Blogs.RecentBlogPosts.cshtml" to control the layout of my shape. The code is the following:
#using Orchard.ContentManagement;
#{
IEnumerable<object> blogPosts = Model.ContentItems.ContentItems;
}
#if (blogPosts != null) {
<div class="container news-slider">
<ul class="slide-images">
#foreach (dynamic post in blogPosts) {
string title = post.Title;
ContentItem item = post.ContentItem;
<img src="/Themes/MountainWestHoops/Content/img/placeholder-700x380.jpg" alt="#title" class="active" />
}
</ul>
#foreach (dynamic post in blogPosts) {
string title = post.Title;
string body = post.Body;
ContentItem item = post.ContentItem;
<div class="featured-story threeD active">
<h1>#title</h1>
<p>#body #Html.ItemDisplayLink("READ MORE", item)</p>
</div>
}
<aside>
<ul class="tabs">
#foreach (dynamic post in blogPosts) {
string title = post.Title;
string url = post.Url;
ContentItem item = post.ContentItem;
<li><h3>#title</h3></li>
}
</ul>
<div class="ad-three-day-trial">
<img src="/Themes/Content/img/placeholder-260x190.gif" />
</div>
</aside>
</div>
}
My HTML is rendering properly, but none of the values that I have specified are showing up.
I am using the "Shape Tracer" module to see what template is being used. What is funny, is that the #Html.ItemDisplayLink("READ MORE", item) is rendering the article's URL, and if I replace the "READ MORE" with the string title, the title renders properly.
What am I doing wrong here that is causing strings to not display? Am I missing a larger point and misunderstanding the fundamentals? The tutorials seems to say that you can simply move around parts, but in this case, I need to have very specific markup for this slider to work.
Seems like your source was http://weblogs.asp.net/bleroy/archive/2011/03/27/taking-over-list-rendering-in-orchard.aspx
That is a rather old post, and the way the title is handled has changed since then.
The DisplayLink works because the only correct property here is post.ContentItem, which is what that API takes. post.Title and post.Body on the other hand are very likely null, which is why you see nothing. To access the title, you can use post.ContentItem.TitlePart.Title and to get the body, post.ContentItem.BodyPart.Text.

Orchard - How to display custom Term fields in a taxonomy field?

I've got a contentType (product) that has a taxonomy field (features). The taxonomy term (product feature term) has been customized to include an image field and a description field.
I'd like for the product detail view to display the image from the term along with the name, but I can't find the property to access it.
I've created the following:
Taxonomy
ProductFeature Taxonomony
Vocabulary: Feat1, Feat2, Feat3
ContentTypes
Product
Fields: Features(Taxonomy)
Product Features Term
Fields: Description(Html), Image(Image)
Views
Fields.Contrib.TaxonomyField-Features.cshtml
<!-- Old Code -->
#if (Model.Terms.Count > 0) {
<p class="taxonomy-field">
<span class="name">#name.CamelFriendly():</span>
#(new HtmlString( string.Join(", ", terms.Select(t => Html.ItemDisplayLink(Html.Encode(t.Name), t.ContentItem ).ToString()).ToArray()) ))
</p>
}
<!-- New Code -->
#if (Model.Terms.Count > 0)
{
<div>
#foreach (var myTerm in Model.Terms)
{
#Display(???)
}
</div>
}
What do replace the question marks with? I'd thought it'd be myTerm.Image but that field doesn't exist on the dynamic object.
I've attached an image of the designer viewer.
If you wanted to use the current dev branch on the module, you could access the TermsPart of the content items, which leads you to all currently applied terms.
If you are using version 0.9 of the module, then you can dynamically have access to the fields by getting a reference to your Content Item, then do contentItem.PARTNAME.FIELDNAME. In the case of a type named Product, and a field name Feature it would be contentItem.Product.Feature. Then if this term has a property named Image, it will be termContentItem.ProductTerm.Image.
I would need more information to give you the exact syntax, like the type of field, exact name of content types. Or you can post the question on the module's codeplex project discussion forum.
As Sebastien helped me figure out over on http://orchardtaxonomies.codeplex.com/discussions/263844
Below is what ended up working.
(The key bit being: contentField = myTerm.ContentItem.Features.TermImage;)
#foreach (var myTerm in Model.Terms)
{
var contentField = myTerm.ContentItem.Features.TermImage;
if (!String.IsNullOrWhiteSpace(contentField.FileName)) {
<p class="image-field">
<img src="#Url.Content(contentField.FileName)" alt="#contentField.AlternateText" width="#contentField.Width" height="#contentField.Height"/>
</p>
}
}

Grails search mechanism

I have the folowing gsp page:
<g:form controller="??" action="??">
<h1>Search</h1>
<g:submitButton name="search" value="Search"/>
<div id="resultsHere">
</div>
</g:form>
What i want to do is, everytime "Search is clicked", the database is searched for that record, lets imagine im looking for book titles. So everytime i write a title, the database finds the books and print every data related to the books. How can i do that=?
My idea is having something similar to this in the div:
<ul>
<g:each in="${bookList}">
<li>Name: ${it.name}, Locale: ${it.isbn}</li>
</g:each>
</ul>
So the point is, when the search button is clicked, the controller that handle that action should redirect the page to the same page, and pass the filtered list of books so it can be printed in the <g:each in="${bookList}"> tag.
I would like opinions about this being the best solution in this case. I could also render the results in the page directly, but i would like to do some css for the lookings so i think that wont be a good idea using render. Any help would be apreciated, and if possible, some lights with the code (specially the filtering part).
I would have one action in your controller, and render out the list.
ie: as pseudo-code (and not complete)
BookController {
def search = {SearchComamnd search ->
def books = []
if(search) {
books = Book.createCritera().list {
and {
title(search.title)
author(search.title)
}
}
}
render [ books:books ]
}
class SearchCommand {
def author
def title
}
}
and then when in your view
<g:form controller="??" action="??">
<h1>Search</h1>
<g:submitButton name="search" value="Search"/>
</g:form>
<g:each in="${books}">
<li class="book">Name: ${it.name}, Locale: ${it.isbn}</li>
</g:each>
you can now use css li.book to decorate the entry.

Resources