In an ASP.NET Core app I want to return custom html from a ViewComponent. I can return custom text, but the html will be encoded instead of being embedded:
public class BannerViewComponent : ViewComponent
{
public async Task<IViewComponentResult> InvokeAsync(string param1, int param2)
{
return Content("<strong>some custom html</strong>");
}
}
I use it in my .cshtml page:
#await Component.InvokeAsync("BannerView")
On the page this will Show as <strong>some custom html</strong> instead of some custom html.
How do I directly return HTML instead of text from the ViewComponent?
If you don't want to return a view you can return HTML this way without a view:
return new HtmlContentViewComponentResult(new HtmlString("Not bold - <b>bold</b>"));
Your ViewComponent could have its own view as well and you can render the html there. The solution would be the following:
public class BannerViewComponent : ViewComponent
{
public async Task<IViewComponentResult> InvokeAsync(string param1, int param2)
{
string model = "<strong>some custom html</strong>";
return View("Index", model);
}
}
Add the following to your Views folder: Views\Shared\Components\BannerViewComponent\Index.cshtml and put the following in the ViewComponent's view:
#model string
#Html.Raw(Model)
You can change the model to be a class instead of just a string so that you can structure the ViewComponent's output, but the key part is the Html.Raw() method to output unencoded html.
Although I would recommend using a view in most cases (and putting all the HTML in the view rather than using it just to output the HTML created by the view component), for very simple components you may want to consider this:
The Invoke() method on the view component does not need to return IViewComponentResult, it can return HtmlString.
For example:
public HtmlString Invoke()
{
return new HtmlString(#"<b>Hello World</b>");
}
Related
in asp.net mvc aspx page i am writing the html input image like this.
<img src="/public/images/"+<%: roleid %>+".jpg" alt="please load the image.." />
in above code roleid -1 is coming from db.but src not forming correctly.
expected result src : /public/images/1.jpg but src not forming correctly.please tell me how to concatenate the string in aspx view engine?
thnaks
Assuming roleid is defined somewhere above in the View, you should form the attribute value in this manner:
src='<%: string.Format("/public/images/{0}.jpg", roleid) %>'
Things to note:
The quotation pattern: single quotes for the whole value, double quotes for strings in C# code.
Value string is generated within the <%: %> tag
There are couple of things i would like talk about.
1) Generating Image URL at runtime in View is not a good practice. You should Use ViewModel for that purpose like this
public class MyViewModel
{
public MyModel m;
public void MyViewModel(MyModel m){this.m=m;}
public string ActualIMageUrl
{
get
{
return "public/Images/"+m.RoleId+".jpg";
}
}
}
Now make your view strongly typed view of this ViewModel class instead of Model.
2)Dont directly use IMG tag in your View, Rather create new method for HtmlHelperClass using extenion method as follows,
public static class MVCExtensions
{
public static MvcHtmlString Image(this HtmlHelper helper, string src, string altText, string height)
{
var builder = new TagBuilder("img");
builder.MergeAttribute("src", src);
builder.MergeAttribute("alt", altText);
builder.MergeAttribute("height", height);
return MvcHtmlString.Create(builder.ToString(TagRenderMode.SelfClosing));
}
}
Now in the View
#model MyViewModel
.
.
.
#Html.Image(Model.ActualImageUrl);
Hope it helped
In my MVC app the controller gets the data (model) from an external API (so there is no model class being used) and passes that to the view. The data (model) has a container in which there are several objects with several fields (string values). One view iterates over each object and calls another view to draw each of them. This view iterates over the fields (string values) and draws them.
Here's where it gets tricky for me. Sometimes I want to do some special formatting on the fields (string values). I could write 20 lines of code for the formatting but then I would have to do that for each and every field and that would just be silly and oh so ugly. Instead I would like to take the field (string value), pass it to a method and get another string value back. And then do that for every field.
So, here's my question:
How do I call a method from a view?
I realize that I may be asking the wrong question here. The answer is probably that I don't, and that I should use a local model and deserialize the object that I get from the external API to my local model and then, in my local model, do the "special formatting" before I pass it to the view. But I'm hoping there is some way I can call a method from a view instead. Mostly because it seems like a lot of overhead to convert the custom object I get from the API, which in turns contains a lot of other custom objects, into local custom objects that I build. And also, I'm not sure what the best way of doing that would be.
Disclaimer: I'm aware of the similar thread "ASP.NET MVC: calling a controller method from view" (ASP.NET MVC: calling a controller method from view) but I don't see how that answers my question.
This is how you call an instance method on the Controller:
#{
((HomeController)this.ViewContext.Controller).Method1();
}
This is how you call a static method in any class
#{
SomeClass.Method();
}
This will work assuming the method is public and visible to the view.
Building on Amine's answer, create a helper like:
public static class HtmlHelperExtensions
{
public static MvcHtmlString CurrencyFormat(this HtmlHelper helper, string value)
{
var result = string.Format("{0:C2}", value);
return new MvcHtmlString(result);
}
}
in your view: use #Html.CurrencyFormat(model.value)
If you are doing simple formating like Standard Numeric Formats, then simple use string.Format() in your view like in the helper example above:
#string.Format("{0:C2}", model.value)
You can implement a static formatting method or an HTML helper, then use this syntax:
#using class_of_method_namespace
...
// HTML page here
#className.MethodName()
or in case of a HTML Helper:
#Html.MethodName()
Controller not supposed to be called from view. That's the whole idea of MVC - clear separation of concerns.
If you need to call controller from View - you are doing something wrong. Time for refactoring.
why You don't use Ajax to
its simple and does not require page refresh and has success and error callbacks
take look at my samlpe
<a id="ResendVerificationCode" >#Resource_en.ResendVerificationCode</a>
and in JQuery
$("#ResendVerificationCode").on("click", function() {
getUserbyPhoneIfNotRegisterd($("#phone").val());
});
and this is my ajax which call my controller and my controller and return object from database
function getUserbyPhoneIfNotRegisterd(userphone) {
$.ajax({
type: "GET",
dataType: "Json",
url: '#Url.Action("GetUserByPhone", "User")' + '?phone=' + userphone,
async: false,
success: function(data) {
if (data == null || data.data == null) {
ErrorMessage("", "#Resource_en.YourPhoneDoesNotExistInOurDatabase");
} else {
user = data[Object.keys(data)[0]];
AddVereCode(user.ID);// anather Ajax call
SuccessMessage("Done", "#Resource_en.VerificationCodeSentSuccessfully", "Done");
}
},
error: function() {
ErrorMessage("", '#Resource_en.ErrorOccourd');
}
});
}
You should create custom helper for just changing string format except using controller call.
I tried lashrah's answer and it worked after changing syntax a little bit.
this is what worked for me:
#(
((HomeController)this.ViewContext.Controller).Method1();
)
You should not call a controller from the view.
Add a property to your view model, set it in the controller, and use it in the view.
Here is an example:
MyViewModel.cs:
public class MyViewModel
{ ...
public bool ShowAdmin { get; set; }
}
MyController.cs:
public ViewResult GetAdminMenu()
{
MyViewModelmodel = new MyViewModel();
model.ShowAdmin = userHasPermission("Admin");
return View(model);
}
MyView.cshtml:
#model MyProj.ViewModels.MyViewModel
#if (#Model.ShowAdmin)
{
<!-- admin links here-->
}
..\Views\Shared\ _Layout.cshtml:
#using MyProj.ViewModels.Common;
....
<div>
#Html.Action("GetAdminMenu", "Layout")
</div>
I have a ASP.NET MVC 4 application that uses database to store pages (HTML), galleries, forms etc... I want to provide users a functionality to call other controller from inside pages.
Simplified problem is how to call render action from database acquired string. Just for example I would like that string contains #Html.RenderAction("Show", "Gallery", new {id=5})
Another option I have to parse string inside a controller and render all sub calls to string before rendering this HTML.
EDIT:
The database would return something like code bellow, service layer can substitute {$gallery$} with #Html.RenderAction("Show", "Gallery", {id=5})
<div class="text">
<h1> title </h1>
<p> this is some random text {$gallery$} </p>
</div>
From your statement
Simplified problem is how to call render action from database acquired
string.
I get that you want to call an action using dynamically provided action-name and controller. If this what you want you could get it using
ViewModel
public class MyViewModel{
public string Action {get;set;}
public string ControllerName {get;set;}
}
Controller
public class MyController : Controller{
public ActionResult MyView(){
return View(new MyViewModel
{ Action ="MyPartialView" , ControllerName = "my"});
}
public ActionResult MyPartialView(){
return PartialView();
}
}
View
#model MyView
....render stuff for the view
#{
Html.RenderAction(Model.Action,Model.ControllerName);
}
Is it possible from a Controller to show a view, and then dependant on what that user selects in dropDownList - render another different view back in the original calling controller? Kind of a "daisy-chaining" effect.
The thinking behind this - is a user selecting a vehicle type - (associated with an ID number) in a view, back in the Controller dependant on what was chosen will render another view immediately displaying HTML according to the vehicle type they chose e.g. an HTML page for car or a boat or aeroplane etc...
If this is possbile can someone point me to a code examaple?
Actual Database Model below - but it is for documents, not vehicles!
check the method paremetares of your action method and return different views baed on that . Something like this.
public ActionResult GetInfo(string id,string vehicleTypId)
{
if(String.IsNullOrEmpty(vehicleTypeId))
{
var vehicle=GetVehicleType(vehicleTypId);
return View("ShowSpecificVehicle",vehicle) ;
}
var genericVehicle=GetVehicle(id);
return View(genericVehicle);
}
EDIT : Saying so, I seriously think you should keep those in 2 seperate Action methods. That makes your code clean and better readable. You may move the common functionality to a function and call if from bothe the action methods id needed. So i would do it in this way
Assuming you have a ViewModel for the first page( displays all vehicletypes)
public class VehicleTypesViewModel
{
//other relevant properties
public IEnumerable Types { set;get;}
public int SelectedTypeId { set;get;}
}
Your GET request for the initial view will be handled by this action result.It gets all the Vehicle types and return that to your view in the ViewModels Types property.
public ActionResult VehicleTypes()
{
VehicleTypesViewModel objVM=new VehicleTypesViewModel();
objVM.Types=dbContext.VehicleTypes.ToList();
return View(objVM);
}
and in your View called VehicleTypes.cshtml,
#model VehicleTypesViewModel
#using(Html.BeginForm())
{
#Html.DropDownListFor(Model.SelectedTypeId,new SelectList(Model.Types,"Text",Value"),"Select")
<input type="submit" value="Go" />
}
Another Action method to handle the form post. You have the selected type id here and you can get the specific details here and return a different view
[HttpPost]
public ActionResult VehicleTypes(VehicleTypesViewModel model)
{
// you have the selected Id in model.SelectedTypeId property
var specificVehicle=dbContext.Vehicles.Where(x=>x.TypeId=model.SelectedTypeId);
return View("SpecificDetails",specificVehicle);
}
Alternatively you can do a Get request for the specific vehicle using RedirecToAction method. I would prefer this approach as it sticks with the PRG pattern.
[HttpPost]
public ActionResult VehicleTypes(VehicleTypesViewModel model)
{
int typeId=model.SelectedTypeId;
return RedirectToAction("GetVehicle",new {#id=typeId});
}
public ActionResult GetVehicle(int id)
{
var specificVehicle=dbContext.Vehicles.Where(x=>x.TypeIdid);
return View(specificVehicle);
}
With Javascript : You can do a get call to the new view from your javascript also. without the HTTPpost to controller. You should add some javascript in your initial view for that
#model VehicleTypesViewModel
//Include jQuery library reference here
#Html.DropDownListFor(Model.SelectedTypeId,new SelectList(Model.Types,"Text",Value"),"Select")
<script type="text/javascript">
$(function(){
$("#SelectedTypeId").change(){
window.location.href="#Url.Action("GetVehicle","Yourcontroller")"+"/"+$(this).attr("id");
});
});
</script>
I think to get a better user experience create a partial view, and load that partial view in a div in the same page via an ajax call.
public ActionResult GetVehicalInfo(string id, string vehicleType)
{
var vehicle = GetVehicleType(id, vehicleTypId);
return PartialView("vehicle);
}
When you use Html.RenderPartial is takes the name of the view you want to render, and renders it's content in that place.
I would like to implement something similar. I would like it to take the name of the view you want to render, along with some other variables, and render the content within a container..
For example:
public static class WindowHelper
{
public static string Window(this HtmlHelper helper, string name, string viewName)
{
var sb = new StringBuilder();
sb.Append("<div id='" + name + "_Window' class='window'>");
//Add the contents of the partial view to the string builder.
sb.Append("</div>");
return sb.ToString();
}
}
Anyone know how to do this?
The RenderPartial extensions are programmed to render directly to the Response object... you can see this in the source code for them:
....).Render(viewContext, this.ViewContext.HttpContext.Response.Output);
This means that if you change your approach a little bit, you can probably accomplish what you want. Rather than appending everything to a StringBuilder, you could do something like this:
using System.Web.Mvc.Html;
public static class WindowHelper
{
public static void Window(this HtmlHelper helper, string name, string viewName)
{
var response = helper.ViewContext.HttpContext.Response;
response.Write("<div id='" + name + "_Window' class='window'>");
//Add the contents of the partial view to the string builder.
helper.RenderPartial(viewName);
response.Write("</div>");
}
}
Note that including System.Web.Mvc.Html allows you access to the RenderPartial() methods.
We are fixing this in MVC 2. You will be able to call Html.Partial() and get the actual contents of the view as a string.
Why not create a second view and have the partial inside that, pass Name as ViewData or in model etc..
Something like:
<div id='<%= ViewData["Name"] + "_Window"%>' class='window'>
<% Html.RenderPartial(ViewData["Name"]); %>
</div>
Hope that helps,
Dan