I have a custom html helper in my App_code folder.
I want to call it from my action and get generated html string.
What should I do?
My MailTemplate.cshtml contents:
#{
Layout = null;
}
#helper ContactUs(string body,string name,string email)
{
<div style="direction:rtl;font-family:Tahoma;color:#3b7a09;">
<span>از طرف:</span><span>#name</span>
<br />
<span>ایمیل:</span><span>#email</span>
<br />
<div style="background-color:#f5dfb2;font-size:13px;">
#body
</div>
</div>
}
Check below code, it has example of html helper method and that helper method use in view.
HTML helper method in App_Code(App_Code\HelperMethods.cshtml)
#helper renderheader(WebViewPage page, string displayText, string ActionName)
{
<div class="row">
<div class="span4">
#page.Html.ActionLink(displayText, ActionName, new { id = 0 }, new { #class = "btn btn-small
btn-primary" })
</div>
<div class="span4">
#page.ViewBag.ErrMsg
</div>
</div>
}
Helper Method Call in View
#HelperMethods.renderheader(this, "AddGroup" , "Create")
Related
I'm working on web app developed in ASP.Net MVC, having a partial view which should be rendered inside its parent view.
Parent view has a HTML Dropdown, on-change event should bind respective data to partial view. But on selection change, the complete parent view is replaced with partial view (child view).
Parent View (Index.cshtml)
<h3>Please Select Group</h3>
#using (Html.BeginForm("EmployeeDeptHistory", "Home", FormMethod.Post))
{
#Html.AntiForgeryToken()
if (ViewBag.DepartmentList != null)
{
#Html.DropDownList("DepartmentName", ViewBag.DepartmentList as SelectList, "-- Select --", new { Class = "form-control", onchange = "this.form.submit();" })
}
}
<div>
#{Html.RenderPartial("_EmployeeDeptHistory");}
</div>
Partial View (_EmployeeDeptHistory.cshtml)
#model IEnumerable<PartialViewApplSol.Models.EmployeeDepartmentHistory>
#if (Model != null)
{
<h3>Employees Department History : #Model.Count()</h3>
foreach (var item in Model)
{
<div style="border:solid 1px #808080; margin-bottom:2%;">
<div class="row">
<div class="col-md-2">
<strong>Name</strong>
</div>
<div class="col-md-5">
<span>#item.Name</span>
</div>
</div>
<div class="row">
<div class="col-md-2">
<strong>Shift</strong>
</div>
<div class="col-md-5">
<span>#item.Shift</span>
</div>
</div>
<div class="row">
<div class="col-md-2">
<strong>Department</strong>
</div>
<div class="col-md-5">
<span>#item.Department</span>
</div>
</div>
<div class="row">
<div class="col-md-2">
<strong>Group Name</strong>
</div>
<div class="col-md-5">
<span>#item.GroupName</span>
</div>
</div>
<div class="row">
<div class="col-md-2">
<strong>Start Date</strong>
</div>
<div class="col-md-5">
<span>#item.StartDate</span>
</div>
</div>
<div class="row">
<div class="col-md-2">
<strong>End Date</strong>
</div>
<div class="col-md-5">
<span>#item.EndDate</span>
</div>
</div>
</div>
}
}
I think the possible mistake is returning partial-view on drop down selection changed.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult EmployeeDeptHistory(FormCollection form)
{
IEnumerable<EmployeeDepartmentHistory> empHistList;
using (IDbConnection con = new SqlConnection(connectionString))
{
empHistList = con.Query<EmployeeDepartmentHistory>("sp_StoredProc", new { DeptId = form["DepartmentName"] }, commandType: CommandType.StoredProcedure);
}
return View("_EmployeeDeptHistory", empHistList);
}
Instead of standard form submit, you need to use jQuery.ajax() function to load partial view inside HTML element without replacing parent view. Here are those steps:
1) Remove onchange event from DropDownList helper, and assign AJAX callback bound to change event:
View
#Html.DropDownList("DepartmentName", ViewBag.DepartmentList as SelectList, "-- Select --", new { #class = "form-control" })
jQuery (inside$(document).ready())
$('#DepartmentName').change(function () {
var selectedValue = $(this).val();
if (selectedValue && selectedValue != '')
{
$.ajax({
type: 'POST',
url: '#Url.Action("EmployeeDeptHistory", "ControllerName")',
data: { departmentName: selectedValue };
success: function (result) {
$('#targetElement').html(result); // assign rendered output to target element's ID
}
});
}
});
2) Remove FormCollection and use a string argument which has same name as AJAX callback argument, also make sure the action method returns PartialView:
Controller
[HttpPost]
public ActionResult EmployeeDeptHistory(string departmentName)
{
IEnumerable<EmployeeDepartmentHistory> empHistList;
using (IDbConnection con = new SqlConnection(connectionString))
{
empHistList = con.Query<EmployeeDepartmentHistory>("sp_StoredProc", new { DeptId = departmentName }, commandType: CommandType.StoredProcedure);
}
return PartialView("_EmployeeDeptHistory", empHistList);
}
3) Finally, don't forget to add ID for target element specified by AJAX callback's success part to load partial view:
View
<div id="targetElement">
#Html.Partial("_EmployeeDeptHistory")
</div>
I have the following cshtml file.
#model Models.AuthorizeUser
#{
ViewBag.Title = "Authorize";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="container">
<div class="card card-container">
<img class="profile-img-card" src="~/Content/images/rblogo_reverse-pms348_000.gif" />
<p> </p>
<form method="POST">
<p>Hello, #Model.Name</p>
<p>A third party application want to do the following on your behalf:</p>
<ul>
#foreach (var scope in Model.Scopes)
{
<li>#scope.ScopeDescription</li>
}
</ul>
<div class ="row">
<div class="col-md-4">
<button class="btn btn-block btn-primary btn-signin" name="submit" type="submit" value="authorize">Grant</button>
</div>
<div class="col-md-8">
<button class="btn btn-block btn-primary btn-signin btn-small-text" name="submit" type="submit" value="logout">Sign in as different user</button>
</div>
</div>
</form>
</div>
</div>
I have my controller file as follows:
public class OAuthController : Controller
{
[HttpGet]
public ActionResult Authorize()
{
logger.Trace("Authorize method entered");
AuthorizeUser authorizeUser;
......
return View(authorizeUser);
}
[HttpPost]
public ActionResult Authorize(AuthorizeUser authorizeUser, string submit)
{
logger.Trace("Authorize with object");
if (Response.StatusCode != 200)
{
logger.Trace("status code " + Response.StatusCode);
logger.Trace("status description " + Response.StatusDescription);
return View("AuthorizeError");
}
..............
}
When the form is displayed, the info is displayed correctly. After I click Grant button, I got Response.StatusCode == 400. Both authorizeUser and submit are null. I am expecting StatuCode == 200 with values of authrizeUser and submit.
Have you tried using Html.BeginForm()?
Instead of using <form method="POST"> you could use Html.BeginForm("Action", "Controller")
I am trying to get a value from a textbox of my View.
This is my View:
#model MyDataIndexViewModel
#{
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12">
<h1>Meine Daten</h1>
</div>
</div>
var item = Model.User;
<div class="row">
<div class="col-xs-6 col-sm-6 col-md-6 myDataTitle">Email</div>
<div class="col-xs-6 col-sm-6 col-md-6">
#Html.TextBox("txtEmail", "", new { placeholder = item.Email})
</div>
</div>
}
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12">
<a class="btn btn-default pull-right" href="/ChangeMyData/Save">Speichern</a>
</div>
</div>
This is my Controller:
[HttpPost]
public ActionResult Save()
{
var email = Request["txtEmail"].ToString();
return View();
}
I get the error just as it says in the Title.
Thank you in advance!
VIEW:
#model MyDataIndexViewModel
#using (Html.BeginForm("Save", "CONTROLLER_NAME"))
{
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12">
<h1>Meine Daten</h1>
</div>
</div>
var item = Model.User;
<div class="row">
<div class="col-xs-6 col-sm-6 col-md-6 myDataTitle">Email</div>
<div class="col-xs-6 col-sm-6 col-md-6">
#Html.TextBox("txtEmail", "", new { placeholder = item.Email, id="txtEmail"})
</div>
</div>
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12">
<a class="submit btn btn-default pull-right">Speichern</a>
</div>
</div>
}
CONTROLLER
[HttpPost]
public ActionResult Save()
{
var email = Request.Form["txtEmail"].ToString();
return View();
}
You can either use strongly-typed viewmodel binding:
View
#model MyDataIndexViewModel
#* other stuff *#
#Html.TextBox("txtEmail", Model.Email)
Controller
[HttpPost]
public ActionResult Save(MyDataIndexViewModel model)
{
var email = model.Email;
return View();
}
Or use a TextBoxFor directly for model binding:
#model MyDataIndexViewModel
#* other stuff *#
#Html.TextBoxFor(model => model.Email)
Or if you still want to use HttpRequest members, Request.Form collection (a NameValueCollection) is available to retrieve text from txtEmail input:
[HttpPost]
public ActionResult Save()
{
var email = Request.Form["txtEmail"].ToString();
return View();
}
Note that Request["txtEmail"] is discouraged due to no compile time safety applied for it, because the key value may retrieved from Request.QueryString, Request.Form or other HttpRequestBase members.
Similar issue:
MVC TextBox with name specified not binding model on post
Access form data into controller using Request in ASP.NET MVC
This used to work... but now the >> anchor tag of the PagedListPager always passes null to the controller for the page value required...
VS 2013 Web Express & MVC 4 with latest package updates for all.
Just like in Scot Allen's MVC 4 intro, I have a partial view with a PagedListPager
The Controller:
public ActionResult Catalog(string Id= "0", int page=1)
{
var CurrentItemsPage = (get-data-blaw-blaw-blaw).ToPagedList(page,18);
var model = new ShowRoomCatalogPackage(){ CurrentItems = CurrentItemsPage};
return View(model);
}
The catalog page
#model craftstore.Models.ShowRoomCatalogPackage
#{
ViewBag.Title = "Catalog";
Layout = "~/Views/Shared/_Details.cshtml";
}
#using (Ajax.BeginForm("Catalog", "Home", new { category = #Model.SelectedCategoryId, page = 1 },
new AjaxOptions
{
UpdateTargetId = "products",
InsertionMode = InsertionMode.Replace,
HttpMethod = "post"
}
)
)
{
<div class="container" >
<div class="row">
<div class="col-lg-10 col-md-5 col-sm-4 dropdown-menu">
#Html.LabelFor(m => m.SelectedCategoryId)
#Html.DropDownList("id", Model.CategoryItems, new { #id = "ddlCategories", onchange = "this.form.submit();" })
</div>
<div class="col-lg-2 col-md-2 col-sm-1">
#Html.ActionLink("Your Cart", "Index", "ShoppingCart", "", new { #class = "btn btn-green btn-lg" })
</div>
</div>
<div class="row">
#Html.Partial("_CatalogPartial", Model.CurrentItems)
</div><!-- row -->
</div><!-- container -->
}
<br />
<br />
#section Scripts
{
<script type="text/javascript">
new AnimOnScroll(document.getElementById('grid'), {
minDuration: 0.4,
maxDuration: 0.7,
viewportFactor: 0.2
});
</script>
}
The partial view:
#model IPagedList<ShowroomCatalog>
<div id="productList">
<div class="col-lg-12 col-md-12 col-sm-12">
<div class="pagedList" data-cs-target="#productList">
#Html.PagedListPager(Model, page => Url.Action("Index", new { category = ViewBag.SelectedCategoryId, page }), PagedListRenderOptions.MinimalWithItemCountText)
</div>
<ul class="grid effect-2" id="grid">
#foreach(var item in Model)
{
var path = String.Format("~/Content/Images/catalog/{0}/{1}", item.OfferType, item.ImagePath);
<li>
<div class="itembox">
<div class="imagebox">
<a href="#Url.Action("Detail", "Home", new { id = item.Id })" title="Detail for #item.CatalogName">
<img class="catalogimg" src="#Url.Content(path)" />
</a>
</div>
<p>#item.CatalogName</p>
</div>
</li>
}
</ul>
</div>
</div><!-- productlist -->
Now the rendered partialview in the browser doesn't have anything in the anchors which may or may not be normal...
<div class="pagedList" data-cs-target="#productList">
<div class="pagination-container"><ul class="pagination"><li class="disabled PagedList-skipToPrevious"><a rel="prev">«</a></li><li class="disabled PagedList-pageCountAndLocation"><a>Showing items 1 through 18 of 65.</a></li><li class="PagedList-skipToNext">»</li></ul></div>
</div>
And when you hover on the >> it doesn't show the page parameter in the URL:
Again, back in the Controller - I get the category (15) but no page parameter or Request.URL parameter is passed to the controller - it's not hiding because of some routing mistake...I think...
How do I get the paging control to work again...???
[EDIT: one more note - the url path on the pager is /controller/action/category/page rather than what shows up on Scot Allen's OdeToFood example where it's equivalent would be /controller/action/category?page=n (like /Home/Catalog/15?page=1 ]
I was missing the JS for the PagedList class anchor element.
var getPage = function () {
var $a = $(this);
var options = {
url: $a.attr("href"),
data: $("form").serialize(),
type: "get"
};
$.ajax(options).done(function (data) {
var target = $a.parents("div.pagedList").attr("data-otf-target");
$(target).replaceWith(data);
});
return false;
};
And this is fired off by :
$(".main-content").on("click", ".pagedList a", getPage);
BUT, this means you need to have your #RenderBody() call in your _Layout.cshtml file wrapped in something with a class of main-content. An example:
<section class="content-wrapper main-content clear-fix">
#RenderBody()
</section>
I have a simple foreach template and inside every element I want an ActionLink but that ActionLink needs to send an Id to edit the element.
The item to be templated:
<div data-bind="template: {
name: 'postsTemplate',
foreach: posts
}">
</div>
The template:
<script id="postsTemplate" type="text/html">
<h2 data-bind="text: Title"></h2>
<p class="post-info">
<p class="post-info" data-bind="text UserName"></p>
<span data-bind="Body"></span>
<p class="post-footer">
#Html.ActionLink("Comments", "IndividualPost", "Post", null, null, "comments", new {id = })
</p>
</p>
</script>
How can I send the actual post Id through the ActionLink? I mean, How I can access to the post's id without using data-bind? (Because it's a helper).
If you would implement your own ActionLink extension along the line of:
public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText,
string actionName, string controllerName,
object routeValues, bool noEncode)
{
var urlHelper = new UrlHelper(htmlHelper.ViewContext.RequestContext);
var url = urlHelper.Action(actionName, controllerName, routeValues);
if (noEncode) url = Uri.UnescapeDataString(url);
var tagBuilder = new TagBuilder("a");
tagBuilder.MergeAttribute("href", url);
tagBuilder.InnerHtml = linkText;
return MvcHtmlString.Create(tagBuilder.ToString(TagRenderMode.Normal));
}
Then you could make your template like:
<p class="post-info">
<p class="post-info" data-bind="text UserName"></p>
<span data-bind="Body"></span>
<p class="post-footer">
#Html.ActionLink("Comments (${CommentCount})", "IndividualPost", "Post",
new {id = "${id}"}, true)
</p>
</p>
the serverside html generated would then look like:
<p class="post-info">
<p class="post-info" data-bind="text UserName"></p>
<span data-bind="Body"></span>
<p class="post-footer">
Comments (${CommentCount})
</p>
</p>
which in turn is a perfect template in my opinion.
The reason for an ActionLink extension is the fact that the normal Html.ActionLink encodes your url to /Post/IndividualPost/%24%7Bid%7D which doesn't work for the template
option 1:
- your posts viewmodel is probably coming from the server, it could contain the link.
{
title:'post title',
commentsUrl:'/Indivdualpost/comments/123'
}
on the server
return new post { comment='post title', commentsUrl=Url.Action('Comments','Individualposts', new {id=1234}); }
and then render the comments url in the template:
<a data-bind="attr: {href:commentsUrl}">comments</a>
option 2:
script using a form
<form id="frm" action="#Url.Action("Comments","IndividualPost")>
<input type="hidden" name="id" id="postid"/>
<!-- template stuff -->
</form>
and in the template
<p class="post-footer">
<a data-bind="click:function(){ $('#postid').val(${$id}); $('#frm').submit(); }">comments</a>
</p>
(the click attribute is quite ugly, should be improved using a binding handler or a viewmodel function ( http://www.knockmeout.net/2011/08/simplifying-and-cleaning-up-views-in.html ))