My models:
public class htmlDump {
public string html { get; set; }
}
public string getSquares() {
var sq = (from s in n.squares
where s.active == true
orderby s.date_created descending
select s.html).First();
return sq;
}
My controller:
public ActionResult index() {
intranetGS.htmlDump sq = new intranetGS.htmlDump {
html = g.getSquares()
};
return View(sq);
}
My View:
#Html.DisplayFor(model => model.html)
All I want is for the html being passed to the view to be rendered as html and not as text. Surely there's something different I can use in the view (instead of .DisplayFor) that will work. Any suggestions?
Thanks very much!
#Html.Raw(Model.html)
NOTE: if this data can be input by the user - make sure it's sanitized.
Related
In my ASP.NET MVC application, I'm trying to pass some values from controller to view.
For this, I'm using the view bag method.
From the controller, the data is passed to the view.
In the view within the for each loop, it also shows the data in the view bag.
But when it runs, I'm getting an error 'object' does not contain a definition for 'cusName'
This is the controller
var SuggestionList = (from c in db.tbl_Main
where c.Suggestion != null orderby c.CreatedDate descending select new
{
cusName = c.CustomerName,
Suggest = c.Suggestion
}).Take(3).ToList();
ViewBag.suggestList = SuggestionList;
return View();
In the view
#foreach(var data in ViewBag.suggestList) {
<li > #data.cusName < /li>
}
Would suggest creating a model class (concrete type) and returning it as List<ExampleModel> type instead of an anonymous list.
public class ExampleModel
{
public string CusName { get; set; }
public string Suggest { get; set; }
}
var SuggestionList = (from c in db.tbl_Main
where c.Suggestion != null
orderby c.CreatedDate descending
select new ExampleModel
{
CusName = c.CustomerName,
Suggest = c.Suggestion
})
.Take(3)
.ToList();
ViewBag.suggestList = SuggestionList;
return View();
MVC newbie question:
I'm picking up a URL of the form go/{mainnav}/{subnav}, which I've successfully routed to the GoController class, method:
public ActionResult Index(string mainnav, string subnav) {
return View();
}
So far, so good. But now I want the view to return different HTML, depending on the values of mainnav or subnav. Specifically, inside a javascript block, I want to include the line:
myobj.mainnav = [value of mainnav parameter];
and, only if subnav is not null or empty:
myobj.subnav = [value of subnav parameter];
How do you pass those parameters to an aspx page that doesn't have a codebehind?
You use a ViewModel class to transfer the data:
public class IndexViewModel
{
public string MainNav { get; set; }
public string SubNav { get; set; }
public IndexViewModel(string mainnav, string subnav)
{
this.MainNav = mainnav;
this.SubNav = subnav;
}
}
Your action method then comes out
public ActionResult Index(string mainnav, string subnav)
{
return View(new IndexViewModel(mainnav, subnav));
}
This means your view has to be strongly typed:
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage<YourNameSpace.IndexViewModel>" %>
In your view, you output the data like so:
myobj.mainnav = <%: Model.MainNav %>;
An alternative solution if you use MVC3, would be to use the dynamic ViewBag:
public ActionResult Index(string mainnav, string subnav)
{
ViewBag.MainNav = mainnav;
ViewBag.SubNav = subnav;
return View();
}
which would be accessed in the page as so:
myobj.mainnav = <%: ViewBag.MainNav %>;
However, I would recommend that you read up on unobtrusive javascript and see if you can improve your design to avoid this specific problem.
If you are using MVC3 I would suggest passing the values into the ViewBag.
ViewBag.MainNav = "xxxx";
ViewBag.SubNav = null;
then on your view page, where you define the JavaScript and add the value.
if you dont have MVC 3 if you use ViewData["MainNav"]), to store your value has the same effect.
Did you try accessing parameters from Request in your view?
i.e.
Request.Params["mainnav"]
or
Request.Params["subnav"]
Works in MVC
i'm using following approach:
ViewModel.class:
public class TitleBodyModel
{
public string Title { get; set; }
public string Body { get; set; }
public TitleBodyModel() { Title = Body = ""; }
public TitleBodyModel(string t, string b) { this.Title = t; this.Body = b; }
}
In the main View:
#Html.Partial("_TitleBody" , new XXX.Models.TitleBodyModel("title", "body" ))
Then in a partial view:
#model XXX.Models.TitleBodyModel
<div class="bl_item">
<div class="bl_title">#Model.Title</div>
<div class="bl_body">#Model.Body</div>
</div>
If i understand this can be a solution:
public ActionResult Index(string mainnav, string subnav)
{
return View(mainnav | subnav);
}
In the Html View you can use View
and after
<%=Model %>
I have this code :
0#Model.Work.Phone
When I use phone like 0#Model.Work.Phone, the # sign is not highlighted. And this looks like this in browser : 0#Model.Work.Phone . I mean the code is displayed instead of the phone number.
When I put a space like this :
0 #Model.Work.Phone
The # sign is higlighted but I want 0 and # to be next to each other. How can I achieve this? Thanks.
On Razor (at least on 2.0 or up) you can use an explicit expression:
0#(Model.Work.Phone)
As an alternative you can use the direct string.format call as offered by Gypsy Spellweaver
Another alternative is using an Razor delegate:
#{
Func<dynamic, object> phoneformat = (item) =>
{
// if we have a string
if (item is String && !String.IsNullOrEmpty(item))
{
// check if the first is not a 0
if (item[0] != '0')
{
// add it
item = String.Format("0{0}", item);
}
}
else if(item is Int32)
{
/// ints never have leading 0, so add it
item = String.Format("0{0}", item);
}
return item;
};
}
0#(Model.Work.Phone) <br/>
0#(Model.Work.PhoneInt)
#phoneformat(Model.Work.Phone) <br/>
#phoneformat(Model.Work.PhoneInt)
Here is the Model I used:
public class Work
{
public string Phone { get; set; }
public int PhoneInt { get; set; }
}
And the Controller that fills it:
public ActionResult Index()
{
var model = new MyModel();
model.Work = new Work {Phone = "612345678", PhoneInt = 612345678};
return View(model);
}
The rendered html content looks like this:
0612345678 <br/>
0612345678
0612345678 <br/>
0612345678
I have populated a dropdown list with values from Database Table. The list gets populated with correct table data but all values have ZERO index in the list. Here is the code to fill dropdown list:
//Get
public ActionResult NewBooking()
{
var db = new VirtualTicketsDBEntities2();
IEnumerable<SelectListItem> items = db.Attractions
.ToList()
.Select(c => new SelectListItem
{
Value = c.A_ID.ToString(),
Text = c.Name
});
ViewBag.Attractions = items;
return View();
}
And on Dropdown View Page:
<div class="editor-label">
#Html.LabelFor(model => model.Attraction)
</div>
<div class="editor-field">
#Html.DropDownList("Attractions")
</div>
For example if table have 3 values A,B, and C. These values are appearing in dropdown list but when I get its selected index in POST request function, it always returns ZERO. Here is the POST submit function:
//Post
[HttpPost]
public ActionResult NewBooking(BookingView booking)
{
try
{
BookingManager bookingManagerObj = new BookingManager();
bookingManagerObj.Add(booking);
ViewBag.BookingSavedSucess = "Booking saved!";
return View("WelcomeConsumer","Home");
}
catch
{
return View(booking);
}
}
booking.Attraction is always ZERO even user selected greater than ZERO index item.
Any suggestions?
I would guess that it is because you are getting a collection of SelectListItems back and not an actual SelectList. Try something like:
<div class="editor-field">
#Html.DropDownListFor(model => model.Attraction, new SelectList(ViewBag.Attractions, "Value", "Text");
It's best not to use ViewBag, you should always use a ViewModel.
Say you have a ViewModel like this:
public class AttractionViewModel
{
public int AttractionId { get; set; }
public SelectList Attractions { get; set; }
}
and modify your view like this - I presume you already have a form in there, the relevant bit is the #Html.DropDownListFor(...) and making sure you have the full namespace to the ViewModel if you haven't already included it in the Views web.config file:
#model AttractionViewModel
#using(Html.BeginForm("NewBooking", "ControllerName"))
{
<div class="editor-label">
#Html.LabelFor(model => model.AttractionId)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.AttractionId, Model.Attractions)
</div>
<input type="submit" value="Submit">
}
and modify your HttpGet like this:
//Get
public ActionResult NewBooking()
{
var db = new VirtualTicketsDBEntities2();
var items = db.Attractions.ToList();
var attractionIdDefault = 0;// default value if you have one
var vm = new AttractionViewModel {
AttractionId = attractionIdDefault,// set this if you have a default value
Attractions = new SelectList(items, "A_ID", "Name", attractionIdDefault)
}
return View(vm);
}
and create an HttpPost ActionResult like this:
// Post
public ActionResult NewBooking(AttractionViewModel vm)
{
var attractionId = vm.AttractionId; // You have passed back your selected attraction Id.
return View();
}
Then it should work.
I know that you have already selected your answer but here is an alternative way of doing what you did. When I started off with ASP.NET MVC I struggled with SelectListItem and found another way of populating my drop down list. I have stuck to this way ever since.
I always have a view model that I bind to my view. I never send through a domain model, always a view model. A view model is just a scaled down version of your domain model and can contain data from multiple domain models.
I have made some modifications to your code and tips, but like I mentioned, it's just an alternative to what you already have.
Your domain model could look like this. Try and give your property names some meaningful descriptions:
public class Attraction
{
public int Id { get; set; }
public string Name { get; set; }
}
You view model could look something like this:
public class BookingViewModel
{
public int AttractionId { get; set; }
public IEnumerable<Attraction> Attractions { get; set; }
// Add your other properties here
}
Do not have your data access methods in your controllers, rather have a service layer or repository expose this functionality:
public class BookingController : Controller
{
private readonly IAttractionRepository attractionRepository;
public BookingController(IAttractionRepository attractionRepository)
{
this.attractionRepository = attractionRepository;
}
public ActionResult NewBooking()
{
BookingViewModel viewModel = new BookingViewModel
{
Attractions = attractionRepository.GetAll()
};
return View(viewModel);
}
[HttpPost]
public ActionResult NewBooking(BookingViewModel viewModel)
{
// Check for null viewModel
if (!ModelState.IsValid)
{
viewModel.Attractions = attractionRepository.GetAll();
return View(viewModel);
}
// Do whatever else you need to do here
}
}
And then your view will populate your drop down like this:
#model YourProject.ViewModels.Attractionss.BookingViewModel
#Html.DropDownListFor(
x => x.AttractionId,
new SelectList(Model.Attractions, "Id", "Name", Model.AttractionId),
"-- Select --"
)
#Html.ValidationMessageFor(x => x.AttractionId)
I hope this helps.
I have tried so many combinations, but cannot get the validation to turn off on this code block
[ValidateInput(false)]
public ActionResult aSavePageCopy()
{
aLoggedIn();
int id = Convert.ToInt32(Request.Form["id"]);
PagesDataContext pdc = new PagesDataContext();
Page p = pdc.Pages.Single(row => row.ID == id);
p.PageCopy = Request.Form["PageCopy"];
pdc.SubmitChanges();
return Redirect("/Admin/aViewPages");
}
It seems that this works for others so I don't see what I'm missing here. The error I get is A potentially dangerous Request.Form value was detected from the client
You could use FormCollection which is safe to access instead of Request.Form (but please don't use it, see below for the real solution to your problem):
[ValidateInput(false)]
public ActionResult aSavePageCopy(FormCollection fc)
{
aLoggedIn();
int id = Convert.ToInt32(fc["id"]);
PagesDataContext pdc = new PagesDataContext();
Page p = pdc.Pages.Single(row => row.ID == id);
p.PageCopy = fc["PageCopy"];
pdc.SubmitChanges();
return Redirect("/Admin/aViewPages");
}
Of course that's an absolutely ridiculous and lousy way to solve the problem. The correct way to do it is to use a view model (of course):
public class MyViewModel
{
public int Id { get; set; }
public string PageCopy { get; set; }
}
and then:
[ValidateInput(false)]
public ActionResult aSavePageCopy(MyViewModel model)
{
aLoggedIn();
PagesDataContext pdc = new PagesDataContext();
Page p = pdc.Pages.Single(row => row.ID == model.Id);
p.PageCopy = model.PageCopy;
pdc.SubmitChanges();
return Redirect("/Admin/aViewPages");
}
or if you are using ASP.NET MVC 3 and wanted to disable validation only for a single property on your view model instead of doing it for the entire request you could decorate this view model property with the [AllowHtml] attribute:
public class MyViewModel
{
public int Id { get; set; }
[AllowHtml]
public string PageCopy { get; set; }
}
and then you no longer need the [ValidateInput(false)] attribute on your action:
public ActionResult aSavePageCopy(MyViewModel model)
{
aLoggedIn();
PagesDataContext pdc = new PagesDataContext();
Page p = pdc.Pages.Single(row => row.ID == model.Id);
p.PageCopy = model.PageCopy;
pdc.SubmitChanges();
return Redirect("/Admin/aViewPages");
}
Not only that we have solved the problem but as you can see you no longer need to write any plumbing code in your controller action parsing around integers and stuff which is the role of the model binder.