play framework (java) : view include another view with a map - view

I have this view:
Profile.scala.html :
#(message: String)
#Main("Welcome") {
Welcome : #message
<br>
<h2>Profile</h2><br>
Edit Profile<br>
Your Environments
**#ViewEnvironment.scala.html ????? how can I include it ?**
}
and I want to include in it, another view (this one):
ViewEnvironment.scala.html:
#(map: Map[String, String])
<h2> Environments :</h2>
<p> Add new Environment</p>
#for((k,v)<- map){
View: #v<br>
Edit : #v<br>
}
<br>
... Can I do that?
Thank you!

Templates are just functions, so if you have a template file in app/views/ViewEnvironment.scala.html it will be compiled to a function you can call as #views.html.ViewEnvironment(envMap).
If the template you're calling from is in the same package, e.g. views.{type-suffix} you can omit the full qualification and just call it as:
#(message: String)
#Main("Welcome") {
Welcome : #message
<br>
<h2>Profile</h2><br>
Edit Profile<br>
Your Environments
#ViewEnvironment(
Map(
"key1" -> "value1",
"key2" -> "value2"
)
)
}
}

Related

Rendering Partial Views in a Loop in MVC3

I have a pretty simple scenario, Model for my view is a List.
Loop through List like
#foreach(CustomObject obj in Model)
{
Html.Partial("_TrackingCustomObject",obj)
}
So i was expecting to have number of partial views according to my list.
Partial View has been developed accordingly.
There is no error on page. It just does not show any data that is supposed to display by partial views.
What is the reason of not showing any data?
You are missing an #:
#foreach(CustomObject obj in Model)
{
#Html.Partial("_TrackingCustomObject", obj)
}
But why writing foreach loops when you can use editor/display templates? Like this:
#model IEnumerable<CustomObject>
#Html.EditorForModel()
and then simply define the corresponding editor template (~/Views/Shared/EditorTemplates/CustomObject.cshtml) that will automatically be rendered for each element of your model:
#model CustomObject
<div>
#Html.EditorFor(x => x.Foo)
</div>
Simple and conventional :-)
You're missing the Razor symbol #:
#foreach(CustomObject obj in Model)
{
#Html.Partial("_TrackingCustomObject",obj)
}
Also make sure your partial view is using the object type CustomObject as the Model.
#model MyProject.Models.CustomObject
<h1>Yeah we're in a partial! #Model.SomeProperty </h1>
To try and drill down to where the error is, try placing some static text inside the PartialView.
<p>Some text</p>
If your collection has 10 items, then you should see 10 of these paragraphs. Next once this works, focus on displaying some property in each item.
#model MyProject.Models.CustomObject
<p>Some text</p>
<p>#Model.SomeProperty</p>
When you are creating html form using #Html.BeginForm() you have to wrap the remaining stuf inside a <div> or other container else the html elements won't get rendered.
Ex.
this won't work
#using(Html.BeginForm())
{
Html.EditorFor(m => m.Name)
}
this will work
#using(Html.BeginForm())
{
<div>
#Html.EditorFor(m => m.Name)
</div>
}
Bit late in the day, but this worked for me in MVC 4:
#foreach (var p in #Model.RelatedCards)
{
Html.RenderPartial("_ThumbPartial", p);
}
Try this:
#Html.RenderPartial("_TrackingCustomObject",obj)
This is too old but someone can use it.
#foreach(CustomObject obj in Model)
{
<text>
Html.Partial("_TrackingCustomObject",obj)
</text>
}

Selecting an alternate EditorFor template for a List

I have an object that represents a food item to order at a restaurant. This object has a list of Modifier Groups (sides, cooking instructions, pizza toppings, whatever) and each list has a list of Modifiers.
Certain Modifier options need to be displayed differently (for example, toppings need to specify left/right/all), even though they are the same data type.
I am trying use #Html.EditorFor and specify the alternate EditorTemplate when required.
In /Views/Shared/EditorTemplates I have ModifierSelection.cshtml and ToppingSelection.cshtml. I am calling them in the following view:
#model MyApp.ViewModels.ModifierSelectionList
<div class="menugroup">
<h3 class="menuname">#Model.ModifierListName: (Select #Model.MaximumSelections)</h3>
<div class="modcountvalidation">#Model.ValidationResults</div>
#Html.HiddenFor(model => Model.ModifierListId)
<table class="menu">
#if (Model.IsToppingsList)
{
#Html.EditorFor(model => Model.ModifierSelections, "ToppingSelection")
}
else
{
#Html.EditorFor(model => Model.ModifierSelections)
}
</table>
</div>
When I try to display an item that requires the "ToppingSelection" EditorTemplate instead of the default, I get the following error:
System.InvalidOperationException was unhandled by user code
Message=The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[MyApp.ViewModels.ModifierSelection]', but this dictionary requires a model item of type 'MyApp.ViewModels.ModifierSelection'.
Source=System.Web.Mvc
So - I have a set of EditorTemplates for a data type. I am trying to use them to display a list of items and I need to be able to select which one to use.
What am I doing wrong?
Thanks!
OK, here is the real solution. Rather than iterating through the list using foreach, I had to iterate using a for loop.
#for (int i = 0; i < Model.ModifierSelections.Count; i++ )
{
if (Model.IsToppingsList)
{
#Html.EditorFor(m => Model.ModifierSelections[i], "ToppingSelection")
}
else
{
#Html.EditorFor(m => Model.ModifierSelections[i])
}
}
Solved!
Apparently, if you send a list type to Html.EditorFor and do not specify a template, it will iterate through the list and display each item using the template that it finds for the item type. If you do specify a template, it will not iterate through the list and send each item to that template, it will attempt to send the entire list to your template, which isn't the right data type.
I fixed it by manually iterating through the list:
#foreach (var modifierSelection in Model.ModifierSelections)
{
if (Model.IsToppingsList)
{
#Html.EditorFor(m => modifierSelection, "ToppingSelection")
}
else
{
#Html.EditorFor(m => modifierSelection)
}
}

How does one iterate over form params with variable keys in Sinatra and Dust.js?

I'm using Sinatra and a client-side template called Dust.js (akin to Mustache) to build a simple form flow. In the initial state, form labels are being passed via JSON
{ "fields" : [ { "title" : "First Name", "name" : "fn" }, { "title" : "Last Name", "name": "ln" } ] }
and interpreted by Dust:
{#fields} <label>{title}: <input type="text" name="{name}" /></label> {/fields}
This is all well and good. After the form is submitted though, I want to reuse the {title} but also iterate through the user-entered values using {name} as the key. What would be nice is to be able to write something like this -- even though it won't work since <%= params[] %> is evaluated before {name}:
<ul>
{#fields}
<li><b>{title}</b>: <%= params[{name}] %></li>
{/fields}
</ul>
And this is where I'm stuck. Even if I create an instance variable in the controller and pass it all of the param values, I'm still not sure how to sync up iteration over both the {title} variables and the params.values.
This is as far as I've gotten:
# controller
post '/submit' do
#v = []
params.values.each do |v|
#v << "#{v}"
end
erb :submit
end
<!-- view -->
<ul>
{#fields}
<% #v.each do |k| %>
<li><b>{title}</b>: <%= k %></li>
<% end %>
{/fields}
</ul>
Any help would be very much appreciated!
I'll answer my own question, in case it's helpful to anyone else out there. Basically, the controller needs to pass the values (in the right order) to the view, then Dust.js can do its thing.
# form.rb
post '/submit' do
# get/store list of input names to be used as keys
#v = ["firstname","lastname","address"] # ...and so on
#vn = []
params.keys.each_with_index do |v, i|
#vn << "#{params[ #v[i] ]}," # comma-delimited, since it's stored as a string in the view
end
erb :submit
end
<!-- submit.erb -->
<ul>
{#fields names="<%= #vn %>"}
<li><b>{title}</b>: {field_vals}</li>
{/fields}
</ul>
/* dust (js) */
var base = dust.makeBase({
field_vals: function(chunk, context) {
// convert string "names" to array
var names = context.get("names").split(',');
// ref with iteration index from context
return chunk.write( names[context.stack.index] );
}
});

#foreach loop in MVC 3

I am new to MVC 3 and have this question to start with,
I have a class defined as
Class abc
{ public string Id { get; set; }
public string str1 { get; set; }
public string Action { get; set; }
public string Name { get; set; }
public string Title {get; set;}
}
on my MVC2 aspx viewpage , I was using this class abc as model and had this code
<%
Model.ForEach(a =>
{ %>
<%= Html.ActionLink(a.Title ,
a.Action , // <-- ActionMethod
a.Name , // <-- Controller Name.
new { key = a.Id }, // <-- Route arguments.
new { title = a.str1 })%>
<br /><br />
<% }); %>
can you please help me convert this piece of code to MVC razor view ?,
#model abc
<%
Model.ForEach(a =>
{ %>
<%= Html.ActionLink(a.Title ,
a.Action , // <-- ActionMethod
a.Name , // <-- Controller Name.
new { key = a.Id }, // <-- Route arguments.
new { title = a.str1 })%>
<br /><br />
<% }); %>
when I try to use #foreach ( var abc in Model) , I get error message , need to implement Ienumerable ? How can I implement using #for Please help or give me pointers.Thanks
The model shows only one object, not a list of objects.
Therefore you should not use ForEach but access the properties directly without a loop as Model.Name etc.
If you want a list of objects, then you need to update your controller to return a list of those by using a generic list, for example.
var abcCollection = new List<abc>();
That should point you in the right direction.
user1005310,
a bit of understanding of the Razor syntax will help here. there are plenty of examples out there via Mr google. However, if you have a LOAD of code to convert, then you have a great little 'tool' out there to help (now OSS, originally developed by Telerik). Take a look at:
https://github.com/telerik/razor-converter
this is basically a convertor that takes an entire set of aspx views and converts them to Razor. I've tried it on a few test projects now and it works to 99% of my satisfaction, the other 1% is being addressed (or i can live with the minor tweaking).
I'd recommend you using a display template. This way you don't need to write any loops. So:
#model IEnumerable<abc>
#Html.DisplayForModel()
and then you define a display template which will automatically be rendered for each element of the model collection (~/Views/Shared/DisplayTemplates/abc.cshtml):
#model abc
#Html.ActionLink(
Model.Title,
Model.Action,
Model.Name,
new { key = Model.Id },
new { title = Model.str1 }
)
<br /><br />
Notice that templates work by convention. They must be placed in either the ~/Views/Shared/DisplayTemplates folder or the ~/Views/SomeController/DisplayTemplates folder depending on whether you want to reuse them between views from multiple controllers or a single controller. ASP.NET MVC first looks in the specific folder for a template and then in the Shared. The name of the file is also important. In this case your model consists of an IEnumerable<abc> where abc is the type of the elements in this collection therefore the display template must be called abc.html.
Same rules apply for editor templates. Just replace display by editor. Editor templates, as their name suggests, are suitable for putting input fields for editing a view model.

Razor behaving strangely?

Razor is playing tricks with me. I have a partial view:
#model ManageMvc.Models.Default.Classes.MvcModule
#{
if (Model.CanExpand)
{
Response.Write("Crazy");
#:TEST
<text>ojiiojjiojiojiojiojiojiojio</text>
Response.Write("Crazy2");
}
else
{
Response.Write("Crazy");
#:TEST
<text>ssssssssdffffffff</text>
Response.Write("Crazy2");
}
}
This is called from this:
#if (Model.Modules.Count > 0)
{
for (var i = 0; i < Model.Modules.Count; i++)
{
Html.Partial("~/Views/UserControls/_MenuItem.cshtml", Model.Modules[i]);
}
....
}
I expected razor to print out whats written inside the Text block and the #: block. But i get nothing. When i run this it just prints CrazyCrazy2 (for each module in the list).
Did i miss something?
Updated
The code that is calling if (Model.Modules.Count > 0) is a partial itself. That one is called from the layout page. So the top code is the second partial being called. Can this make any difference?
Layout -> MainMenu (partial) -> CreateMenuItem (partial)
Updated
This is the new code: (_MenuItem.cshtml inside Shared->DisplayTemplates)
#model ManageMvc.Models.Default.Classes.MvcModule
#{
if (Model.CanExpand)
{
#:TEST
<text>ojiiojjiojiojiojiojiojiojio</text>
}
else
{
#:TEST
<text>ssssssssdffffffff</text>
}
}
Partial view MainMenu that is calling the menu item:
#Html.DisplayFor(x => x.Modules, "_MenuItem")
Now this breaks on that line and i get the following error:
The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[ManageMvc.Models.Default.Classes.MvcModule]', but this dictionary requires a model item of type 'ManageMvc.Models.Default.Classes.MvcModule'.
Put an # when calling the Html.Partial helper and avoid using Response.Write in an ASP.NET MVC view:
for (var i = 0; i < Model.Modules.Count; i++)
{
#Html.Partial("~/Views/UserControls/_MenuItem.cshtml", Model.Modules[i]);
}
Also instead of writing some ugly loops I would strongly suggest you using templated helpers. So replace the for loop in your layout with this simple helper:
#Html.DisplayFor(x => x.Modules)
and then define the display template (~/Views/Shared/DisplayTemplates/MvcModule.cshtml) which will be rendered for each element of the Modules collection:
#model ManageMvc.Models.Default.Classes.MvcModule
#if (Model.CanExpand)
{
#:TEST
<text>ojiiojjiojiojiojiojiojiojio</text>
}
else
{
#:TEST
<text>ssssssssdffffffff</text>
}
See how easier this is?

Resources