asp.net mvc3 disable masterpage for view - asp.net

How can I disable the usual _Layout.cshtml for one view.
I try to use the content of the view aboutuser.cshtml to populate a div using ajax. Do you think this is a correct approch?
$('#SelectUser').click(function () {
$('#userPlace').html('<strong>Loading...</strong>');
$.post('InfoFor?userSelect=' + ($('#usersoption:selected').val()), function (data) {
$('#userPlace').html(data);
});
});

Inside this view/partial:
#{
Layout = null;
}
or from the controller action serving it return a PartialView instead of a View:
public ActionResult Foo()
{
return PartialView();
}

Related

How to re-open modal window after ModalState is invalid with the errors shown?

I have a login modal window which has validation. The problem is that I can not re-open the modal window when the validation fails.
So, I have this controller: Index() which returns the View of the homepage. On that homepage, I have the modal window which has the validation.
But after clicking the submit button (Login() controller), and after validation failure, the URL is /Index/Login and I can not pass ViewBag value which tells the modal to re-open.
Here is the code from both controllers:
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Login(Users user)
{
if (ModelState.IsValidField("username") && ModelState.IsValidField("password"))
{
if (Users.Login(user))
{
//some custom logic
return RedirectToAction("../Dashboard/Dashboard");
}
else
{
ViewBag.LoginError = "Wrong username/password";
}
}
else
{
}
return View("Index");
}
I really need help guys. I am trying to solve this the whole day!
PS: I work with Razor syntax on the front.
If you have the section scripts in your _Layout.cshtml which is in the /Views/Shared/_Layout.cshtml then paste the below code at the end of the /Views/Home/Index.cshtml.
#section scripts
{
<script>
#if(ViewBag.LoginError == "Wrong username/password")
{
WriteLiteral("$('#login-modal').modal('show');");
}
</script>
}
This can be done ajax way too however above is the solution to your question.
If the section scripts is not defined in _Layout.cshtml, then define this section at the end of the _Layout.cshtml just like below.
#RenderSection("scripts", required: false)

Partial refresh in ASP using ajax

How do you do a partial refresh of a page using Ajax in cshtml?
As I understand it, Ajax is required. In my scenario, in my index page I have a table where each row has a program (a batch file) and a Run button. Beneath the table I have the a space for the program output. I would like this to populate (I'm happy to wait for the program to finish just now) without having to refresh the rest of the page.
Code is below, but in summary I have one model for the table data, one model for the selected program log/output. The controller for the index page creates both and passes them in to a view model, which is passed to the view. When the Run button is hit an Index overload method in the controller handles the running of the program and 'getting' the output. It also populates the appropriate model in the VM (possibly not ideal and I'm open to suggestions to improve it).
The overloaded method currently returns a PartialViewResult and the output/logging has it's own PartialView (as I'll want to reuse it elsewhere). This is also why it has a separate model. In the PartialView break points are hit, but it doesn't appear on the page in the browser.
I'm using ASP.NET-MVC-4 with Razor.
View (Index.cshtml)
<script src="https://code.jquery.com/jquery-1.10.2.js"></script>
#model ViewModels.UpdateTestViewModel
#{ ViewBag.Title = "Update Test"; }
#{
<table>
#* Headers *#
<tr>
<td>Programs</td>
</tr>
#* Data *#
<tr>
<td>#Model.ProgramName</td>
<td style="min-width:75px"><input id="btnRun" type="button" value="Run" /></td>
</tr>
</table>
<div id="log">
#Html.Partial("ScriptLog", Model.Log)
</div>
<script>
$("input[type=button]").on("click", function () {
var NAME = ($(this).parent().siblings(":first")).text();
$.post("/UpdateTest/Run", { input: NAME });
});
</script>
}
Partial View
#model Models.ScriptLog
#if (Model != null && Model.Log.Any(x => !string.IsNullOrWhiteSpace(x)))
{
<fieldset>
<legend>Log</legend>
#foreach (string entry in Model.Log)
{
<p>#entry</p>
}
</fieldset>
}
Script Log
public IEnumerable<string> Log { get { // returns log } }
ViewModel
public class UpdateTestViewModel
{
public string ProgramName { get { return "My Program"; } }
public ScriptLog Log { get { return _log; } }
private readonly ScriptLog _log;
public UpdateTestViewModel(ScriptLog log)
{
_log = log;
}
}
Controller
public ActionResult Index()
{
if (SessionFacade.CurrentUpdateTestLog == null)
{
ScriptLog log = new ScriptLog();
SessionFacade.CurrentUpdateTestLog = log; // Store in Session
}
UpdateTestViewModel vm = new UpdateTestViewModel(SessionFacade.CurrentUpdateTestLog);
return View(vm);
}
[ActionName("Run")]
public PartialViewResult Index(string input)
{
ExecuteScript.ExecuteUpdateTestScript(input); // Run batch file
UpdateTestLog(input); // Get log and update in Session
return PartialView("ScriptLog", SessionFacade.CurrentUpdateTestLog);
}
Since you are making an $.post() you need to decorate your /UpdateTest/Run action with [HttpPost].
You also don't define a success handler so, while you are making the request, you never do anything with it.
$.post("/UpdateTest/Run", { input: NAME })
.done(function(partialResult) {
$("#log").html(partialResult);
})
.fail(function(jqxhr, status, error) {
console.log(jqXhr, status, error);
});
With much help and patience from #Jasen I got a working solution which was to extend the existing Ajax, so that it looks like:
$("input[type=button]").on("click", function () {
var NAME = ($(this).parent().siblings(":first")).text();
$.post("/UpdateTest/Run", { input: NAME })
.done(function (partialResult) {
$("#log").html(partialResult);
})
});
Note I also have added the [HttpPost] attribute in the controller

Multiple forms rendered in one page

In my Index view, I render(action) 3 other views, Create, Edit and List. The Create and Edit views are both forms to manipulate data in a database. When I push edit button in the List View the Create form should disappears and the Edit form should appear. So Create and Edit shouldn't be shown at the same time.
When I don't render the views in one view, everything works fine. But because I don't want to switch pages, I want to render the views in one page. Here is the problem. My Create form and List view works fine when I render them in one page. But when I also want to render my Edit form, I get errors.
One thing that happens is that the Create form puts de data in the database 2 times. Also when I don't put validated data in my form, the edit form appears at the same time that the create form is shown. The third problem is when I put the edit button in my List. The create form disappears and the edit form apears. So this works, but when I want to save the changed data, I get a hex string error. When I restart the application, the data isn't changed, but there is new record with the changed data.
I guess there is a problem with the id string. But I can't fix it.
So I have 4 views (index, create, list and edit)
Create, list and edit all have their own model.
And I use one controller for the views / models
The controller (CarsController):
public class CarsController : BaseController
{
public ActionResult Index()
{
return View();
}
public ActionResult List()
{
List<Car> carsInDb = CarRentalContext.Cars.FindAll().ToList();
return View(carsInDb.ConvertAllToViewModels());
}
[HttpGet]
public ActionResult Create(string id)
{
if (String.IsNullOrEmpty(id))
{
return View();
}
return null;
}
[HttpPost]
public ActionResult Create(InsertCarViewModel insertCarViewModel)
{
if (ModelState.IsValid)
{
Car car = insertCarViewModel.ConvertToDomain();
CarRentalContext.Cars.Insert(car);
Response.Redirect("Cars", true);
}
return View(insertCarViewModel);
}
[HttpGet]
public ActionResult Edit(string id)
{
if (String.IsNullOrEmpty(id))
{
return null;
}
Car car = CarRentalContext.Cars.FindOneById(new ObjectId(id));
return View(car.ConvertToUpdateViewModel());
}
[HttpPost]
public ActionResult Edit(UpdateCarViewModel updateCarViewModel)
{
if (ModelState.IsValid)
{
Car modifiedCar = updateCarViewModel.ConvertToDomain();
CarRentalContext.Cars.Save(modifiedCar);
return RedirectToAction("Index");
}
return View(updateCarViewModel);
}
}
The index view:
#model MvcApplication1.ViewModels.UpdateCarViewModel
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<div>
#{Html.RenderAction("Create", Model);}
</div>
<div>
#{Html.RenderAction("Edit", Model);}
</div>
<div>
#{Html.RenderAction("List", Model);}
</div>
</body>
</html>
Instead of show/hide the views for create and edit views try to replace one with another, using ajax to get the result of the action. This way you will have only one view in the page.
Do something like this:
<script type="text/javascript">
function renderActionInDiv(idcar, action)
{
$.ajax({
type: "POST",
url: action, //or "/Cars/Edit"
data: { id = idcar},
success: function (ajxData) {
if (typeof callback !== 'undefined') {
$("#div-editOrCreate").html(ajaxData);
}
},
async: asyncCall
});
}
</script>
<a onclick='renderActionInDiv(3, "Edit")'>edit car<a/>
<a onclick='renderActionInDiv(0, "Create")'>create new car<a/>
<div id="div-editOrCreate">
#{Html.RenderAction("Create", Model);}
</div>

A Contact page with ASP.NET MVC 3

I have a contact page and this page shall either show a form or a success message or a failure message, so basically something like this:
#model MyApp.Models.ContactData
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div>
...Some static content...
If page was opened the first time
-> Render a form here
Else If form was posted and data successfully processed
-> Render a success message here
Else If form was posted but error occurred during processing
-> Render a failure message here
...Some static content...
</div>
I don't know what's the best way to achieve this with MVC 3. Do I create three completely separate views (which is something I'd like to avoid because of the static content which would be the same for all three views)? Or could I create three partial views and then decide based on an additional flag I could put into the model class which partial view to render? Or can I inject somehow the partial views dynamically from the controller into the view?
The controller I have so far looks like this:
public class ContactController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(ContactData contactData)
{
if (ModelState.IsValid)
{
ContactService service = new ContactService();
bool result = service.Process(contactData);
return ?; // What do I return now? It must somehow depend on result.
}
else
return View(contactData));
}
}
I had a similar page and behaviour with ASP.NET WebForms and the solution was there to put the three variable blocks of markup into asp:Panel controls and then switch on or off the Visible flag of those panels from code-behind. I guess I need quite another approach with ASP.NET MVC to reach the same goal.
What is the best way?
Thank you for suggestions in advance!
You can try this way:
[HttpPost]
public ActionResult Index(Contact contactData)
{
if (ModelState.IsValid)
{
ContactService service = new ContactService();
if (service.Process(contactData))
{
TempData["Success"] = "Your success message.";
return RedirectToAction("Index");
}
else
{
TempData["Error"] = "Your fail message.";
}
}
return View(contact);
}
Perhaps use the ViewBag to help achieve all this. Of course it's a dynamic, so you can add & check for any prop you want/need/expect.
[HttpPost]
public ActionResult Index(ContactData contactData)
{
if (ModelState.IsValid)
{
ContactService service = new ContactService();
bool result = service.Process(contactData);
ViewBag.ContactSuccess = true;
}
else
{
ViewBag.ModelStateErr= "some err";
}
return View(contactData));
}
Then in your View:
if (ViewBag.ContactSuccess !=null && ((bool)ViewBag.ContactSuccess))
{
//thanks for posting!
}
else
{
if (ViewBag.ModelStateErr !=null)
{
//show that we have an err
}
else
{
//we have no err nor a 'true' contact success yet
//write out the form
}
}
Looks like that you can issue an ajax call on the client side, and based on the Json result, you can render different content from the client side.
I'd suggest coding up three different Views
index.cshtml
contactSuccess.cshtml
contactFail.cshtml
Then in your Controller, you'll have similar code as before
public class ContactController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(ContactData contactData)
{
if (ModelState.IsValid)
{
ContactService service = new ContactService();
bool result = service.Process(contactData);
return View("contactSuccess.cshtml");
}
else
return View("contactFail.cshtml", contactData);
}
}
This way each view has an independent and you don't have a big inline IF block in the middle of your markup.
Alternatively (and this is how I'd do it) you can have the index.cshtml contain three partials...
_ContactForm.cshtml
_ContactSuccess.cshtml
_ContactFail.cshtml
and then you can load the partial views into the index view, and even swap them out dynamically using AJAX.

how to send a message to a view ajax-like

I want to know about a pattern to do this. I have a controller with method1()
method1(){
return View();
}
[httpost]
method1(string something){
return View(object);
}
[httpost]
method2(int? id){
return redirectToaction("method1");
}
View:
<div>
beginform(){
textfield
submit button
}
</div>
<div>
if(viewbag.something != null){
beginform("method2", "controller", new{id=number}){
<span>#model.info</span>
submit button
}
}
</div>
and this displays a view this view has a form a text field and submit and this calls method1() but with the HTTPPOst and in the same view i display another form which will call method2() my question is how can i display a message in the view? like "user has been deleted" without having to create another view. Is there another way of doing this in asp mvc or do i have to include ajax?
I tried setting a viewBag inside method2, but since method2 redirectsaction to method1 it somehow does not stay, and it is not displayed in the view.
Thanks!
You could use TempData which is preserved between a single redirect:
public ActionResult method1()
{
return View();
}
[HttpPost]
public ActionResult method1(string something)
{
return View(something);
}
[HttpPost]
publicActionResult method2(int? id)
{
TempData["message"] = "User has been deleted";
return RedirectToAction("method1");
}
and in the view display the message:
<div>#TempData["message"]</div>
If there is no message in TempData it will simply display an empty div. You could further check if TempData["message"] != null in the view if you didn't want the empty div.

Resources