mvc 3 equivalent to <asp:repeater> function? - c#

I have a website in Asp.Net that I am trying to port to MVC 3 and I have only worked with MVC 2 before. I stumbled across the following asp function
<div class="popup-holder">
<ul class="popups">
<asp:Repeater runat="server" ID="ourTeamRepeater" OnItemDataBound="ourTeamRepeater_ItemDataBound">
<ItemTemplate>
<asp:Panel ID="pnlTeamMember" runat="server">
<li id="TeamMember" runat="server" class="memberImage">
<asp:Image runat="server" ID="memberImg" />
</li>
<div class="popup">
<div class="img-holder">
<asp:Image runat="server" ID="memberImgBig" />
</div>
<div class="popup-text-t">
<div class="close">
close
</div>
</div>
<div class="popup-text">
</div>
<div class="popup-text-b">
</div>
<div class="holder">
<asp:Literal ID="memberDescription" runat="server" />
</div>
</div>
</asp:Panel>
</ItemTemplate>
</asp:Repeater>
</ul>
it looks like maybe this works similarly to a for loop, but I'm not quite positive how to convert it to MVC 3 architecture.

Porting an existing WebForms application to ASP.NET MVC is not only about blindly translating line by line some WebForms view code that you have. You should take into account the semantics of the target platform. For example converting this asp:Repeater into an ugly foreach loop instead of taking into account things like view models, display templates would not be very good.
So in ASP.NET MVC you start by designing view models:
public class MemberViewModel
{
public int Id { get; set; }
public string Description { get; set; }
}
then you design a controller action which populates this view model:
public ActionResult Index()
{
IEnumerable<MemberViewModel> model = ...
return View(model);
}
then you write a strongly typed view in which you invoke a display template:
#model IEnumerable<MemberViewModel>
#Html.DisplayForModel()
and then you define a display template which will be rendered for each element of the collection (~/Views/Shared/DisplayTemplates/MemberViewModel.cshtml):
#model MemberViewModel
<li id="TeamMember" class="memberImage">
<img src="Url.Action("ThumbnailImage", new { id = Model.Id })" alt=""/>
</li>
<div class="popup">
<div class="img-holder">
<img src="Url.Action("FullImage", new { id = Model.Id })" alt=""/>
</div>
<div class="popup-text-t">
<div class="close">
close
</div>
</div>
<div class="popup-text"></div>
<div class="popup-text-b"></div>
<div class="holder">
#Html.DisplayFor(x => x.Description)
</div>
</div>
Now you will notice the two additional ThumbnailImage and FullImage controller actions that will allows us to fetch the images of the members given the member id. For example:
public ActionResult ThumbnailImage(int id)
{
byte[] thumbnail = ...
return File(thumbnail, "image/jpeg");
}
Now that's more like ASP.NET MVC. As you can see it's a totally different pattern than classic WebForms.

You're quite right to suppose that the MVC equivalent of an asp:Repeater is
<% foreach( var item in Model )
{ %>
<!-- Your HTML Markup -->
<% } %>

You're right about it being similar to a for loop. A simple implementation might look like this:
<div class="popup-holder">
<ul class="popups">
<%foreach(var item in Model.Items) { %>
<div id="pnlTeamMember">
<img src="<%: item.MemberImageSrc %>" ID="memberImg" />
<div class="popup">
<div class="img-holder">
<img src="<%: item.MemberImgBigSrc %>" ID="memberImgBig" />
</div>
<div class="popup-text-t">
<div class="close">
close
</div>
</div>
<div class="popup-text">
</div>
<div class="popup-text-b">
</div>
<div class="holder">
<%: item.MemberDescription %>
</div>
</div>
</div>
<% } %>
</ul>
You'll notice that there are no longer any controls with runat="server", nor are there any events linked to handlers in the code-behind. Instead, we are assuming that the controller has populated the Model object with objects representing the data that we need to display. That is the role of the controller when using MVC.

A repeater is just a loop that provides databinding so that you can access the items in the collection that you are looping. If you look in the ourTeamRepeater_ItemDataBound method you will find the code that uses the databound items to populate the elements in the item template with data.
Usually you can just use a foreach loop in MVC to loop the items. Example:
<% foreach (var item in items) { %>
<div class="holder">
<%= item.Description %>
</div>
<% } %>

Related

I want to use the Same View to show different result in different nav bar using MVC razor Engine.I have designed a page using html tags

I have designed a page using html tags. i have used the same code in a View in my MVC application. The page has three tabs tab1, tab2 and tab3.
#using (Html.BeginForm("ViewName", "Home", FormMethod.Post))
{
<div class="col">
<ul class="nav nav-tabs" id="myTab" role="tablist">
<li class="nav-item">
<a class="nav-link active" id="tab">Search</a>
</li>
<li class="nav-item">
<a class="nav-link tab" id="tab2" href="#tab2"</a>
</li>
<li class="nav-item">
<a class="nav-link tab" id="tab3">Details</a>
</li>
</ul>
</div>
<div class="col-auto text-right">
#Html.TextBoxFor(Model => Model.Name) <!--This is my text box to enter the text.-->
<input type="submit" class="btn btn-primary" value="Search" name="Search" action="ViewName"><!--On submitting it, it will hit the "test" action method in the Controller.-->
</div>
<div class="tab-pane fade" id="tab2" role="tabpanel" aria-labelledby="results-tab">
<table id="Table" class="table" style="width:100%">
<thead>
<tr>
<th>Name</th>
<th>Name1</th>
</tr>
</thead>
<tbody>
<tr>
<td>name2</td>
<td>name2</td>
</tr>
</tbody>
</table>
</div>
<div class="tab-pane fade" id="details" role="tabpanel" aria-labelledby="details-tab">Details</div>-- the above is the table to which i want to bind the data and show the result and it is in the same view.
}
The above is the HTML code i am using in my view of the MVC code. i have three tabs in my Html code.
In my Tab1:
I have a text box with my search button.
I am binding the text box to the required model property.
After i have entered the text and hit the search button. It would call an API and give the list which contains or equals the required text.In my controller i have used the [HttpPost] attribute.I am posting the form on clicking the submit button.
public IActionResult ViewName()
{
NameModel obj = new NameModel();
return View("ViewName", obj);
}
[HttpPost]
public IActionResult ViewName(NameModel obj1)
{
NameModel model = new NameModel();
-- Call the api and take out the Json response.
--Bind the json response to the Model.
--Send the model back to the same view but different tab.
return View("ViewName", model);
}
Now i want to display the result in the Tab2 in the grid format which is in the Same View.
The tab2 contains the table. How do i bind the resulted model value to it since it is in the same view.
I dont want to use the JQuery. i want to use any .net core concepts to implement it.
Can someone please tell me how to do it.
Solution 1: Partial view included in different views
I would go for another type of implementation. It looks like the views are indeed different from each other and the fact that you require different models for each tab tells me the same.
If that's the case, Check the partial view guide here
The main idea is to create the navbar as a reusable partial view, and include it in every other View (that is every other tab) you want to use.
Solution 2: Use the jquery option
MVC uses html/css and javascript to render clientside items. It is not non-MVC practice to use JQuery with it, it is in fact a common practice.
Solution 3: Use razor logic check w3schools entry
You can add checks like this below in your razor and have one model
#if (Model.Tab == 1)
{
<div class="col-auto text-right">
#Html.TextBoxFor(Model => Model.Name) <!--This is my text box to enter the text.-->
<input type="submit" class="btn btn-primary" value="Search" name="Search"
action="ViewName"><!--On submitting it, it will hit the "test" action method in the
Controller.-->
}
</div>
Now in your backend, change the Model.Tab and have an overall model like this:
public MyModel {
public int Tab;
public TabOneModel;
public TabTwoModel;
public TabThreeModel;
}
While I have seen this quite a lot it has major disadvantages.
You can't apply an overall validation.
Your code will become very complicated in a single function. It violates multiple principles and can't be easiy unit tested.
IMO, you could post the name using ajax and return the partial view where locates the Tab2 content, and display the result to the main view.
Refer to my following steps:
1.ViewName.cshtml
#model NameModel
<div class="col">
<ul class="nav nav-tabs" id="myTab" role="tablist">
<li class="nav-item">
<a class="nav-link active" href="#tab" role="tab" data-toggle="tab">Search</a>
</li>
<li class="nav-item">
<a class="nav-link tab" href="#tab2" role="tab" data-toggle="tab">Grid</a>
</li>
<li class="nav-item">
<a class="nav-link tab" href="#tab3" role="tab" data-toggle="tab">Details</a>
</li>
</ul>
</div>
<div class="tab-content">
<div role="tabpanel" class="tab-pane fade in active" id="tab">
<div class="col-auto text-right">
<input asp-for="#Model.Name" id="myText" />
<input type="button" class="btn btn-primary" onclick="myFunction()" value="Search" id="Search" name="Search" /><!--On submitting it, it will hit the "test" action method in the Controller.-->
</div>
</div>
<div role="tabpanel" class="tab-pane fade" id="tab2">
<div id="Tab2Content">
</div>
</div>
<div role="tabpanel" class="tab-pane fade" id="tab3">ccc</div>
</div>
#section Scripts{
<script>
function myFunction() {
var name = document.getElementById("myText").value;
$.ajax({
type: 'POST',
url: '/Home/ViewName',
data: { name: name },
error: function (result) {
console.log("error");
},
success: function (result) {
$("#Tab2Content").html(result);
}
});
}
</script>
}
2.Post method:
[HttpPost]
public IActionResult ViewName(NameModel obj1)
{
NameModel model = new NameModel();
-- Call the api and take out the Json response.
--Bind the json response to the Model.
--Send the model back to the same view but different tab.
return PartialView("_Tab2PartialView", tab2model);
}
3.Partial View (located at /Views/Shared/_Tab2PartialView.cshtml) to display the grid
#model tab2model
#*or #model List<tab2model>*#
#*grid view*#
<table id="Table" class="table" style="width:100%">
<thead>
<tr>
<th>Name</th>
<th>Name1</th>
</tr>
</thead>
<tbody>
<tr>
<td>name2</td>
<td>name2</td>
</tr>
</tbody>
</table>

Output csharp into a html class

Trying to acheive outputing a variable from csharp into the class of a html element.
Currently i'm doing this:
#foreach (var cocktail in Model)
{
<li>
<div class="drink">
<div class="drink-sprite " ></div>
</div>
<div class="details">
<div class="name">#cocktail.CocktailName</div>
<div class="price">£#cocktail.Price.ToString("0.00")</div>
<div class="description">#cocktail.Description</div>
</div>
</li>
}
essentially in the div class="drink-sprite" I want to put the drink type in the glass so an image is shown based on the class types. so drink-sprite martini - which is dervied from cocktail.type.
Anythoughts?
#foreach (var cocktail in Model)
{
<li>
<div class="drink">
<div class="drink-sprite #cocktail.Type"></div>
</div>
<div class="details">
<div class="name">#cocktail.CocktailName</div>
<div class="price">£#cocktail.Price.ToString("0.00")</div>
<div class="description">#cocktail.Description</div>
</div>
</li>
}
Why don't you just print the variable directly in the class declaration?
Like so:
<div class="drink-sprite #cocktail.Type" ></div>
This should output the cocktail.Type directly into the HTML as you'd need.
If cocktail.Type is null or "" (empty), then this will still work, and won't affect your current implementation.

ASP.net Image to ListView From Data

Morning guys, Using MS Visual Studio 2012, ASP.net/C# 3.5.(not MVC)
I have a list view that is bound in code behind from my model.
It currently displays on screen as columns with 0, 1 or ''. i would like to replace these at runtime with images (tick or cross) and show no image if the value is ''.
Now i have the following snippet of code:
<asp:ListView ID="lvSearchUser" runat="server">
<div class="hidden">
<div id="<%#Eval("userid") %>" class="target">
<div class="emptyTitle" style="width:680px;">
<div class="videosViewed">Videos Viewed</div><div class="module13">Module13</div><div class="module12" >Module12</div>
<div class ="module11" >Module11</div><div class="module10">Module10</div><div class="totalTime">Total Time</div>
</div>
<div class="videosViewed" ><%#Eval("VideosViewed") %> </div>
<div class="module13"> <%#Eval("ModuleNum13") %> </div>
<div class="module12"> <%#Eval("ModuleNum12") %> </div>
<div class="module11"> <%#Eval("ModuleNum11") %> </div>
<div class="module10"> <%#Eval("ModuleNum10") %> </div>
<div class="totalTime"> <%#Eval("TotalTime") %> </div>
</div>
</div>
<div style="clear:both"></div>
code behind is :
private void ShowGrid()
{
//dgvUserResults.DataSource = null;
List<ModelSearchUser> dbuser = runSQL.GetUserFinal(GetSearchInput(), GetCountryInput(), GetUserTypeInput(), GetGroupInput(), GetCodeUsageInput(), GetCompletedInput());
lvSearchUser.DataSource = dbuser;
this.lvSearchUser.DataBind();
}
please note this is not a datagrid its listview that has divs wrapped inside to act like a grid.
So anyone have a solution to this? (unfortunately one that also works with IE7...shudders*)
Assuming that ModuleNum13 is and int in the datasource when binding, how about:
<div class="module13">
<asp:Image id="tick" runat="server" Visible='<%# Eval("ModuleNum13") is int && ((int)Eval("ModuleNum13")) == 1 %>' ImageUrl="/image/tick.jpg" />
<asp:Image id="cross" runat="server" Visible='<%# Eval("ModuleNum13") is int && ((int)Eval("ModuleNum13")) == 0 %>' ImageUrl="/image/cross.jpg" />
</div>
And similar for the other fields. This is not elegant but should work...

How can I use #using in partial view?

I have a grid filled with notes and I want to be able to add a new note. This works using two different views, but that makes the CreateNote view open a new window. I want this to open in the same window. So instead of a View I use a PartialView. This works, but the "#using (UI.koform(Model, null))" is seen as html so the knockoutjs doesn't work. How can I make this work in a partial view?
Code:
The view:
[...]
<script type="text/javascript">
(function() {
$('#load-partial').click(function() {
$('#partial').load('#Url.Action("CreateNote", "Entity", new {modelEntity = #Model.meta.entity})');
});
})();
</script>
<div id="partial"></div>
<button type="button" id="load-partial">Create Note</button>
The action:
public ActionResult CreateNote(
[ModelBinder(typeof(Models.JsonModelBinder))]
NoteModel Model, string cmd, string modelEntity)
{
[...]
return PartialView("CreateNotePartial",Model);
}
The Partial view:
<%# Control Language="C#" Inherits="test.Web.Framework.Core.ViewUserControl<test.Web.Framework.Areas.Administration.Models.NoteModel>" %>
#using (UI.koform(Model, null))
{
<div class="ui-state-highlight ui-corner-all highlight" data-bind="visible: meta.message">
<span class="ui-icon ui-icon-info"></span><strong data-bind="text: meta.message">
</strong>
</div>
Subject:
<input type="text" data-bind="value:subject" />
<span data-bind="text: subject"></span>
<br />
Text:
<input type="text" data-bind="value:text" />
<br />
set values
<div class="dialogButtons">
<button onclick="$('##Model.meta.modelname').koform('submit');">
Save</button>
</div>
}
It looks like you're mixing View engines. Your control definition is using ASPX View engine syntax (<%# %>) while your using statement is using Razor. My guess is if you changed the code to this it would work:
<% using (UI.koform(Model, null))
{ %>
<%-- HTML --%>
<% } %>

.net Html.RenderAction returns binary instead of HTML. Huh?

I'm not sure exactly what I'm doing wrong here.
I have an action which returns a partial view:
public class SharedController : BaseController
{
public ActionResult StudentPoll()
{
WAM.X2O.FuelUpToPlayContext db = new WAM.X2O.FuelUpToPlayContext(WAM.Utilities.Config.ConnectionString);
WAM.X2O.StudentPoll m = (from s in db.StudentPolls where s.IsActive == true select s).SingleOrDefault();
return PartialView("StudentPoll", m);
}
}
I implement the action like this:
<%Html.RenderAction("StudentPoll", "Shared");%>
The partial view looks like this:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl< Fuel_Up_To_Play.Models.Shared.StudentPollModel >" %>
<%if(ViewData.Model != null){ %>
<div class="block">
<div class="holder">
<div class="frame">
<h2 class="poll">Student Poll</h2>
<!-- TODO - Student Poll has a form screen, and results screen.
Results anim is here to demo what should happen after submision -->
<form action="/Shared/SubmitStudentPoll" method="post" class="poll-form" <%if(ViewData.Model.StartingState == Fuel_Up_To_Play.Models.Shared.StudentPollModel.PollStates.RESULTS){%>style="display:none"<%} %>>
<fieldset>
<span><%=ViewData.Model.StudentPoll.Question %></span>
<input type="hidden" id="student_poll" name="student_poll" value="<%=ViewData.Model.StudentPoll.ID %>" />
<%foreach(WAM.X2O.StudentPollAnswer answer in ViewData.Model.StudentPoll.RelatedStudentPollAnswers){ %>
<div class="row">
<input type="radio" class="radio" id="answer_<%=answer.ID %>" name="poll_answer" value="<%=answer.ID %>"/>
<label for="answer_<%=answer.ID %>"><%=answer.AnswerText%></label>
</div>
<%} %>
<input id="submitBtn" type="image" style="display:none" class="image" src="/Content/images/btn-submit-05.gif" />
</fieldset>
</form>
<div class="progress-box" <%if(ViewData.Model.StartingState == Fuel_Up_To_Play.Models.Shared.StudentPollModel.PollStates.FORM){%>style="display:none"<%} %>>
<span><%=ViewData.Model.StudentPoll.Question %></span>
<%int answerCounter = 0;
foreach(WAM.X2O.StudentPollAnswer answer in ViewData.Model.StudentPoll.RelatedStudentPollAnswers){ %>
<div class="box">
<span class="names"><%=answer.AnswerText%><strong class="quesPctTxt" rel="<%=ViewData.Model.AnswerPercentages[answerCounter] %>"></strong></span>
<div class="progress-bar"><span class="quesPctBar"></span></div>
</div>
<%
answerCounter++;
} %>
</div>
</div>
</div>
</div>
<script type="text/javascript" src="/Scripts/studentpollscript.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$("input.radio[name='poll_answer']").change(function() {
$("#submitBtn").show();
});
$("#submitBtn").click(function() {
$(".poll-form").ajaxForm(
{ dataType: 'json',
success: function(json) {
alert(json.Success);
}
}
);
});
});
</script>
<%} %>
Natually, I would expect this approach to return HTML. But no. Instead it appears that binary is being rendered in the browser. Obviously I'm doing something wrong but I don't know what.
Here's what is rendered in the browser:
http://screencast.com/t/Mjg1OWJj
Any ideas folks? I'm stumped but I'm sure it's something simple that I'm missing.
I would guess that it simply isn't setting the content type correctly. What does a network trace (fiddler, etc) show? Perhaps try using View("StudentPoll", m); instead of PartialView(...)?
Also; be careful - many of those <%= look unsafe, i.e. not html-encoded.

Categories

Resources