MVC 4 Updating a view with a controller action - asp.net-mvc

I'm new to MVC. I want to be able to change a button/divs/textboxes text when a view's button is clicked. I found a tutorial online that showed me the following but when I click the button I'm getting redirected to another page. That page shows the text instead. I haven't touched the default Global.aspx
View
#using (Ajax.BeginForm("ExamineTextBox", new AjaxOptions { UpdateTargetId = "result" }))
{
#Html.TextBox("textBox1")
<input type="submit" value="Button" />
<span id="result" />
}
Controller
public string ExamineTextBox(string textBox1)
{
if (textBox1 != "Initial Data")
{
return "This text is MVC different from before!";
}
return String.Empty;
}

Make sure you have included the jquery.unobtrusive-ajax.js script to your page.
If you are using the default bundles (take a look at ~/App_Start/BundleConfig.cs - you will see a jqueryval bundle defined which combines and minifies all ~/Scripts/jquery.unobtrusive* and "~/Scripts/jquery.validate*" files):
#Scripts.Render("~/bundles/jqueryval")
and if not using bundles you could include only this script individually:
<script type="text/javascript" src="~/scripts/jquery.unobtrusive-ajax.js"></script>
It is this script that is required for Ajax.* helpers to work. As it name indicates it unobtrusively AJAXifies them. It depends on jQuery so make sure you have that one included as well.
Side note: In ASP.NET controller actions should return ActionResults, not strings:
public ActionResult ExamineTextBox(string textBox1)
{
if (textBox1 != "Initial Data")
{
return Content("This text is MVC different from before!");
}
return Content(String.Empty);
}
Here's how your full view code might look:
#{
Layout = null;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title></title>
<link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
<meta name="viewport" content="width=device-width" />
</head>
<body>
#using (Ajax.BeginForm("ExamineTextBox", new AjaxOptions { UpdateTargetId = "result" }))
{
#Html.TextBox("textBox1", "Initial Data")
<input type="submit" value="Button" />
<span id="result" />
}
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/jqueryval")
</body>
</html>
and the controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult ExamineTextBox(string textBox1)
{
if (textBox1 != "Initial Data")
{
return Content("This text is MVC different from before!");
}
return Content(String.Empty);
}
}

Related

Open Rotativa print dialog automatically

I am using Rotativa to generate a PDF of a view with the intention of printing it.
I have the following code
public ActionResult PrintTicket(string tempTickID)
{
//var tick = ctx.vw_printTicket.Where(e => e.noTicket == tempTickID).FirstOrDefault();
// return View(tick);
var report = new ActionAsPdf("PrepareTicket", new { tempTickID = tempTickID });
return report;
}
ActionAsPdf allows me to open the "PrepareTicket" view as a pdf and then I can print.
Problem
The problem for me is this, The pdf takes over my entire page and while I can print I don't have access to my program's menus anymore cause it's now a PDF view.
Questions
Is it possible that I call the print dialog automatically instead of showing the pdf?
I think will work for my situation.
Regards
Hi I have tried to create a sample which will solve your issue.
Model
public class Ticketinfo
{
public string name { get; set; }
public int quantity { get; set; }
}
Created a Controller which has 3 Action Method
public class GenerateController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult PrintTicket(string tempTickID)
{
return new ActionAsPdf("RotativaPartialViewAsPdf", new { tempTickID = tempTickID });
}
public ActionResult RotativaPartialViewAsPdf(string tempTickID)
{
Ticketinfo Ticketinfo = new Ticketinfo()
{
name = "Demo",
quantity = 5
};
return PartialView("_RotativaPartialViewAsPdfl", Ticketinfo);
}
}
Partial View
#model WebApplication6.Models.Ticketinfo
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
<link href="~/Content/bootstrap.css" rel="stylesheet" />
</head>
<body>
<div class="container">
<table class="table">
<tr class="info">
<td>Lot</td>
<td>Name</td>
<td>Quantity</td>
</tr>
<tr class="success">
<td>#Model.name</td>
<td>#Model.quantity</td>
</tr>
</table>
</div>
</body>
</html>
Index View
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<div>
<iframe src="#Url.Action("PrintTicket", "Generate", new {tempTickID = "1"})"
width="800px" height="600px">
</iframe>
</div>
</body>
</html>
Output

Error of populating menu items permenantly and unwantedly in each postback in MVC

I have a problem. In order to make it understandable, I want to denote my layout. layout is as follows:
Menu side is implemented by NavController. Here is the content of the NavController:
public class NavController : Controller
{
private IProductRepository repository;
public NavController(IProductRepository repo) {
repository = repo;
}
[ChildActionOnly]
public PartialViewResult Menu(string category = null)
{
ViewBag.SelectedCategory = category;
//IEnumerable<string> categories = repository.Products
//.Select(x => x.ProductCategory)
//.Distinct()
//.OrderBy(x => x);
IEnumerable<string> categories = Actions.GetirTumAksiyonları();
return PartialView(categories);
}
}
At the Menu action method, some strings populated and become visible at the Menu side.
There are many controllers defined in my project that manipulates the Content of the project, and they have buttons that post back to server. Whenever I click at one of these buttons, menu strings permenantly populated. Here is my _Layout.cs:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>#ViewBag.Title</title>
<link href="~/Content/Site.css" type="text/css" rel="stylesheet" />
<link href="~/Content/themes/base/jquery-ui.css" rel="stylesheet" />
<script src="~/Scripts/jquery-1.8.2.js"></script>
<script src="~/Scripts/jquery-ui-1.8.24.min.js"></script>
</head>
<body>
<div id="header">
<div class="title">Lojman Bilgi Sistemi</div>
</div>
<div id="categories">
#{ Html.RenderAction("Menu", "Nav"); }
</div>
<div id="content">
#RenderBody()
</div>
How can I overcome the issue? thanks in advance.
You can write your Menu method this way. Cheers :)
[ChildActionOnly]
public PartialViewResult Menu(string category = null)
{
// Logic
}

login is not pulling through LoginStudentNumber from the view to controller

When i run my login I cannot seem to pull through the LoginStudentNumber. It pulls through the password, but not the LoginStudentNumber. Please see what exaclty is wrong with my code.
Login Controller:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using RMS.DAL;
using RMS.Models;
namespace RMS.Controllers
{
public class LoginController : Controller
{
RMSContext db = new RMSContext();
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
//
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
public ActionResult Login(Login model, int? LoginStudentNumber, string LoginPassword)
{
//Login user = db.Logins
Login user = db.Logins.Find(LoginStudentNumber);
if (user == null)
{
ViewBag.Name1 = "Invalid User ID";
return View();
}
else
{
if (user.LoginPassword.Equals(LoginPassword))
{
return View("../Home/Index", model);
}
else
{
ViewBag.Name2 = "Invalid Password";
return View();
}
}
}
}
}
Login View:
#model RMS.Models.Login
#{
Layout = null;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Creative - Bootstrap 3 Responsive Admin Template">
<meta name="author" content="GeeksLabs">
<meta name="keyword" content="Creative, Dashboard, Admin, Template, Theme, Bootstrap, Responsive, Retina, Minimal">
<link rel="shortcut icon" href="img/favicon.png">
<title>Login</title>
<!-- Bootstrap CSS -->
<link href="~/Content/bootstrap.min.css" rel="stylesheet" />
<!-- bootstrap theme -->
<link href="~/Content/bootstrap-theme.css" rel="stylesheet" />
<!--external css-->
<!-- font icon -->
<link href="~/Content/elegant-icons-style.css" rel="stylesheet" />
<link href="~/Content/font-awesome.css" rel="stylesheet" />
<!-- Custom styles -->
<link href="~/Content/style.css" rel="stylesheet" />
<link href="~/Content/style-responsive.css" rel="stylesheet" />
<!-- HTML5 shim and Respond.js IE8 support of HTML5 -->
<!--[if lt IE 9]>
<script src="js/html5shiv.js"></script>
<script src="js/respond.min.js"></script>
<![endif]-->
</head>
<body style="background-color:white">
<img src="~/img/thrupps.png" style="width: 300px; height: 200px; margin: 0px 490px 0px 490px; " />
<div class="col-md-12">
<div class="login-wrap">
#using (Html.BeginForm("Login", "Login", System.Web.Mvc.FormMethod.Post, new { #class = "login-form" }))
{
<p class="login-img"><i class="icon_lock_alt"></i></p>
<div>
#ViewBag.Name1
</div>
<div class="input-group">
<span class="input-group-addon"><i class="icon_profile"></i></span>
#Html.TextBoxFor(a => a.LoginStudentNumber, "LoginStudentNumber", htmlAttributes: new { #class = "form-control" })
</div>
<div>
#ViewBag.Name2
</div>
<div class="input-group">
<span class="input-group-addon"><i class="icon_key_alt"></i></span>
#Html.TextBoxFor(a => a.LoginPassword, "LoginPassword", htmlAttributes: new { #class = "form-control" })
</div>
<input type="submit" id="button" class="btn btn-lg btn-success btn-block " value="Login" />
}
</div>
</div>
</body>
</html>
Login Model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace RMS.Models
{
public class Login
{
public int LoginID { get; set; }
[Required]
public int LoginStudentNumber { get; set; }
[Required]
public string LoginPassword { get; set; }
}
}
and also to add, when I type the following code, I identifies "Logins" and not "Login" even though my table in titled "Login".
Login user = db.Logins.Find(LoginStudentNumber);
Whilst Michael Fung's answer did tickle me I believe this answer is what you're after...
Your logic action's parameter is spelt incorrectly. You put LoginStudentNumer when it should be LoginStudentNumber
public ActionResult Login(Login model, int? LoginStudentNumer, string LoginPassword)
Update
You can ensure the client enters a number by utilising the type attribute and setting its value to number.
#Html.TextBoxFor(a => a.LoginStudentNumber, "LoginStudentNumber", htmlAttributes: new { #class = "form-control", type = "number" })
Update 2
still having a problem. when i run the login page, it doesn't take me
to the home page when my username and password is correct,
The reason it doesn't take you to your home page is because the following is invalid
return View("../Home/Index", model);
You should be returning a redirect to the browser
return RedirectToAction("Index", "Home");
nor does it show me errors for when my username and password is
incorrect. could there be something wrong in the controller.
If you want to display the errors you can return the model along with any model state Errors.
public ActionResult Login(Login model, int? LoginStudentNumber, string LoginPassword)
{
//Login user = db.Logins
Login user = db.Logins.Find(LoginStudentNumer);
if (user == null)
{
ModelState.AddModelError("", "Invalid User Id");
return View(model);
}
if (user.LoginPassword.Equals(LoginPassword))
{
return RedirectToAction("Index","Home");
}
ModelState.AddModelError("", "Invalid Password");
return View(model);
}
Then in your view you would need to output the error message but using...
#Html.ValidationSummary()

MVC4 model binding with two complex models

I have an action on my controller that takes two parameters that should be captured when a form is posted:
[HttpPost]
public ActionResult Index(MyModel model, FormAction action)
The idea is that the model data should be captured in MyModel and the button that the user pressed should be captured in FormAction:
public class MyModel
{
public string MyValue { get; set; }
}
public class FormAction
{
public string Command { get; set; }
}
Here is my view:
#model TestApp.Models.MyModel
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<div>
#using (Html.BeginForm("Index", "Home"))
{
#Html.TextBoxFor(x => x.MyValue)
<input type="submit" value="OK" name="command" />
<input type="submit" value="Cancel" name="command" />
}
</div>
</body>
</html>
If I add another string parameter to the action called 'command' then the value of the button comes through but it doesn't get bound to the Command property on the FormAction parameter - the parameter is always null.
If I add a Command property to MyModel then the button value does come through.
Is there something in MVC model binding that prevents more than one complex model to be bound in one action method?
The metter is that Html.BeginForm sends only model from top statenent: #model TestApp.Models.MyModel. If I clearly understand what you whant to do, the better solution will be to create ViewModel:
public class ViewModel
{
public MyModel myModel {get; set;}
public FormAction formAction {get; set;}
}
Change View as follows:
#model TestApp.Models.ViewModel
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<div>
#using (Html.BeginForm("Index", "Home"))
{
#Html.TextBoxFor(model=> model.myModel.MyValue)
#Html.TextBoxFor(model=> model.formAction.Command)
<input type="submit" value="OK" name="command" />
<input type="submit" value="Cancel" name="command" />
}
</div>
</body>
</html>
And change your Action to:
[HttpPost]
public ActionResult Index(ViewModel model)
I've got to the bottom of this and the reason it wasn't working was simply because the parameter was named action. This is pretty much the equivalent of a keyword in MVC and it is used by the MVC framework to identify the action to be executed.
Changing the parameter name to something else means that the Command property comes through as expected!

jquery unobtrusive doesn't emit validation attributes client-side when having a child grid

I have setup a little test project that I hope will explain my problem.
I have a parent class that has a property containing all its children of type Child. In the MVC view I list all the children in a table and to have the form post back my children and map them to the parent property automatically I render them like:
#Html.TextBox(string.Format("Children[{0}].ChildName", childIndex), child.ChildName)
In the controller I have marked property ChildName to be required. The problem I have is that jquery unobtrusive validation does not emit any data validation attributes. Everything validates nice on the server but not on the client (obviously because there are no attributes for jquery validation to find on these inputs).
Please have a look at the code:
VIEW
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<div>
<form action="#Url.Action("Save")" method="post">
#Html.TextBox("Name", (string)Model.Name)
<table>
<tr><td>Child name</td></tr>
#{var childIndex = 0;}
#foreach (var child in (List<GridValidationTest.Controllers.Child>)Model.Children)
{
<tr><td>#Html.TextBox(string.Format("Children[{0}].ChildName", childIndex), child.ChildName)</td></tr>
childIndex++;
}
</table>
<br /><button>Submit</button>
</form>
</div>
</body>
</html>
CONTROLLER
namespace GridValidationTest.Controllers
{
public class Parent
{
[Required]
public string Name { get; set; }
public IList<Child> Children { get; set; }
}
public class Child
{
[Required]
public string ChildName { get; set; }
}
public class MyController : Controller
{
//
// GET: /My/
public ActionResult Index()
{
var parent = new Parent { Name = "Parent name" };
parent.Children = new List<Child>
{
new Child {ChildName = "First child"},
new Child {ChildName = "Second child"}
};
return View("Index", parent);
}
public ActionResult Save(Parent parent)
{
return View("Index", parent);
}
}
}
The client validation on property Name of Parent class works fine as expected.
How should I render the children to have client-side validation to work as I expect?
You need to bind the fields in your view to your model. Instead of using:
#Html.TextBox(string.Format("Children[{0}].ChildName", childIndex), child.ChildName)
Use
#Html.TextBoxFor(model => model.Children[childIndex])
#Html.ValidationMessageFor(model => model.Children[childIndex])
Also make sure you are including the right jquery javascript files on your page. Something like:
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
Also make sure that in your web config you have ClientValidationEnabled and UnobtrusiveJavaScriptEnabled turned on like so:
<appSettings>
....
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
....
</appSettings>

Resources