Implement and populate view model db first - asp.net-mvc

I have created a page were the user searches for a book and the book details are loaded using partial view. I have successfully done this.
The action method in the controller used to do this:
[HttpGet]
public ActionResult LoanSearch(string q)
{
var loans = GetLoans(q);
return PartialView(loans);
}
private List<Loan> GetLoans(string searchString)
{
return db.Loans
.Where(a => a.Book.Name.Contains(searchString))
.ToList();
}
As you can see the LoanSearch action method is decorated with HTTPGET.
The View for this:
#using (Html.BeginForm())
{
foreach (var item in Model)
{
<ul>
<li>#item.ISBN</li>
<li>#item.Book.Name</li>
<li>#item.Book.Author</li>
<li> #item.FinePrice</li>
</ul>
#Html.ActionLink("Return Book", "LoanSearch", new { id = item.LoanId });
}
}
What I would like to do is update the finePrice in loans db and change onLoan from 1 to 0 in the books db. This should happen when the user clicks on the above Html.ActionLink above.
To achieve this I created the following HTTPPOST action method and also used a view model as I needed to update 2 tables (Loan,Book) at the same time.(is a view model needed?)
[HttpPost]
public ActionResult LoanSearch(BookReturnVM model, string searchString)
{
var bookquery = db.Loans.Where(a => a.Book.Name.Contains(searchString));
var loanquery = db.Loans.Where(a => a.Book.Name == model.BookTitle);
var finePrice = db.Loans.Where(g => g.FinePrice == model.FinePrice);
BookReturnVM model1 = new BookReturnVM
{
OnLoan = model.OnLoan,
FinePrice = model.FinePrice,
};
if (ModelState.IsValid)
{
var fine = db.Loans.FirstOrDefault(g => g.FinePrice == model.FinePrice);
var bookLoan = db.Loans.FirstOrDefault(a => a.Book.Name.Contains(searchString));
if (bookLoan != null)
{ //changes the onloan status to 1 which makes it 'on loan'
bookLoan.Book.OnLoan = 0;
};
db.Entry(bookLoan).State = EntityState.Modified;
db.SaveChanges();
}
return View();
I would like the finePrice found in the Loan table to be updated based on the calculation below. The finePrice calculation is done in the Loan model:
private decimal? _FinePrice;
public decimal? FinePrice
{
get
{
if(DateTime.Now>CheckOutDate)
{
this._FinePrice= ((DateTime.Now - CheckOutDate).Days)*0.50M;
}
else
{
this._FinePrice = 0M;
}
return this._FinePrice;
}
set
{
this._FinePrice = value;
}
}
In conclusion when I search for a book, the details of the book appears(in partial view,which it does), and when I click a button(on the same partial view page) the OnLoan (book table) changes from 1 to 0 and the finePrice (loan table)is updated for that particular book.
I assume the problem lies within the HTTP POST action method but do not know how to solve this in order to solve the above question.
Thanks for your time

You can do something like this:
Tables:
USE [Breaz]
GO
/****** Object: Table [dbo].[Loan] Script Date: 6/26/2017 11:15:15 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Loan](
[LoanId] [int] IDENTITY(1,1) NOT NULL,
[ISBN] [varchar](20) NULL,
[Name] [varchar](20) NULL,
[Author] [varchar](20) NULL,
[FinePrice] [money] NOT NULL,
CONSTRAINT [PK_Loan] PRIMARY KEY CLUSTERED
(
[LoanId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
Controller
public class HomeController : Controller
{
[HttpGet]
public PartialViewResult LoanSearchByIdAndUpdate(int id)
{
//DO your database update here
//I will change the find to 2.37
Loan loan = new Loan();
var bookName = String.Empty;
using (BreazEntities26 db = new BreazEntities26())
{
loan = db.Loans.Find(id);
loan.FinePrice = 2.37M;
bookName = loan.Name;
}
IList<Loan> loans = new List<Loan>();
loans.Add(loan);
return PartialView("_LoanSearch", loans););
}
[HttpGet]
public PartialViewResult LoanSearch(string q)
{
var loans = GetLoans(q);
return PartialView("_LoanSearch", loans););
}
private List<Loan> GetLoans(string searchString)
{
using (BreazEntities26 db = new BreazEntities26())
{
return db.Loans
.Where(a => a.Name.Contains(searchString))
.ToList();
}
}
IndexValid2.cshtml
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>IndexValid2</title>
<script src="~/Scripts/jquery-1.12.4.min.js"></script>
#*MAKE SURE to put the next script in*#
<script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script>
<script type="text/javascript">
$(function () {
$('#passSearchValue').click(function () {
var searchValue = $('#q').val();
this.href = this.href + '?q=' + encodeURIComponent(searchValue);
});
})
</script>
</head>
<body>
<div>
Search for book:
#Html.TextBox("q", null, new { id = "q" })
#*https://stackoverflow.com/questions/5838273/actionlink-routevalue-from-a-textbox*#
#Ajax.ActionLink(
"Search",
"LoanSearch",
null,
new AjaxOptions
{
UpdateTargetId = "result",
InsertionMode = InsertionMode.Replace,
HttpMethod = "GET"
},
new { id = "passSearchValue" })
</div>
<div id="result"></div>
</body>
</html>
partial view in shared, _LoanSearch.cshtml
#model IEnumerable<Testy20161006.Models.Loan>
#foreach (var item in Model)
{
<ul>
<li>#item.ISBN</li>
<li>#item.Name</li>
<li>#item.Author</li>
<li> #item.FinePrice</li>
</ul>
#Html.ActionLink("Update", "LoanSearchByIdAndUpdate", new { id = item.LoanId });
<p />
#Html.ActionLink("Return to Search", "IndexValid2");
}

Related

ASP.NET MVC, 3 static dropdownlists. It should parse all the values at once, but it doesn't.

Hi guys sorry for the short post ;0)
I have a view with tre dropdownlists, then i sumbit the form it should parse all the selected values at once to the database, but it doesn't.
Here is my code:
the view....
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>SaveRatings</title>
</head>
<body>
<div>
#using (Html.BeginForm("SaveRatings", "Scout"))
{
int id = 3;
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
for (int i = 0; i < id; i++)
{
#Html.DropDownList("Value", (IEnumerable<SelectListItem>)ViewBag.Value, "Vælg en værdi fra 1 - 20", new { #class = "form-control" })<br/>
}
<input type="submit" value="Save" />
}
</div>
</body>
</html>
the controller and the ValueDropDownList method
public ActionResult SaveRatings()
{
ValueDropDownList();
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SaveRatings(string Value)
{
using (Connection db = new Connection())
{
List<Rating> rt = new List<Rating>();
rt.Add(new Rating
{
Value = Value
});
//For every obejct in the list, it should add the items....
foreach (var item in rt)
{
db.Ratings.Add(item);
}
db.SaveChanges();
}
return View("GetProperties");
}
The ValueDropDownList method
public void ValueDropDownList()
{
List<SelectListItem> valueitems = new List<SelectListItem>();
valueitems.Add(new SelectListItem { Text = "1", Value = "1" });
valueitems.Add(new SelectListItem { Text = "2", Value = "2" });
valueitems.Add(new SelectListItem { Text = "3", Value = "3" });
ViewBag.Value = valueitems.ToList();
}
Your current view code is going to render 3 SELECT element with the name "Value". When you submit the form, the form data will have 3 keys with the name "Value" and each ones value is your selected option value.
Now since it is sending an array (because all three dropdown names are same), you need to udpate your action method parameter to an array. Then you can loop through this array and save it.
public ActionResult SaveRatings(string[] Value)
{
using (var db = new Connection())
{
foreach (var item in Value)
{
var t=new Rating
{
Value = item
};
db.Ratings.Add(t);
}
db.SaveChanges();
}
return RedirectToAction("Index");
}

handle 'open in a new window' when clicked on ajax.ActionLink which point to action that returns partial view

Hello I've got an action which gets some data from database and returns a partial view
In the partial view there are ajax.actionLinks which when clicked execute the same ImportShow action but this time with new data; and as you see in the cshtml - then update only the with the new data.
The problem I'm trying to solve is - if a user clicks 'Open in new Window' or 'open in new tab' in the new window you will see loaded only this partial view. And I can't think of a way how to make redirect and reload the whole page only in this cases. (after all the link point to an action method that RETURNS A PARTIAL VIEW).
public virtual ActionResult ImportShow(String id, String menuID, string articlegroupID, int? counter)
{
GroupMenu p_GroupMenu = new GroupMenu();
p_GroupMenu.MenuHistory = p_GetMenuHistory.ToList();
p_GroupMenu.MenuLeft = p_GetMenuLeft.ToList();
return PartialView("ImportShow", p_GroupMenu);
}
As
model MvcBeaWeb.GroupMenu
<div class="importPartUpdate">
<ul id="products">
#{
if (Model != null)
{
foreach (MvcBeaDAL.WebServiceBeaMenu item in Model.MenuLeft)
{
<li id="#item.ID">
<div class="imageTilesShow">
<a title= #item.SpecialWord>
<img src="#item.ImageFile" alt='#item.SpecialWord)' id="ImageProducts" class="imageTilesShow">
#Ajax.ActionLink(#item.SpecialWord, "ImportShow", new { id = Model.LanguageName,menuID=#item.ID},new AjaxOptions { UpdateTargetId = "importPartUpdate", HttpMethod = "GET", InsertionMode = InsertionMode.Replace })
</a>
</div>
</li>
}
}
}
</ul>
</div>
There are a few posts that having this issue before, you can check out this and this. Basically what happens is: when you click the "ajax" link, it is a AJAX call, therefor the partial view was rendered and everything works as expected. However, when you right click to view the page a new tab or new window in the browser, it is NOT a AJAX call, but you're returning a partial view, the new tab or window will still return a partial view. That's why you only see the partial view.
To illustrate what I meant:
here's the code snippet.
public class HomeController : Controller
{
List<Person> people = new List<Person>()
{
new Person { Name = "Larry", Age = 10},
new Person { Name = "Jessie", Age = 11},
new Person { Name = "Ben", Age = 12},
new Person { Name = "Victor", Age = 13},
new Person { Name = "Tom", Age = 14},
new Person { Name = "Suresh", Age = 15},
new Person { Name = "Jim", Age = 16},
};
public ActionResult Index()
{
return View();
}
public ActionResult GetPerson()
{
Random r = new Random();
int i = r.Next(0, people.Count);
if (Request.IsAjaxRequest())
{
return PartialView(people[i]); //return partial if it's a ajax call
}
else
{
return View(people[i]); // return view if it's NOT a ajax call
}
}
}
Index View:
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#Ajax.ActionLink("replace", "GetPerson", new AjaxOptions { UpdateTargetId = "replaceMe", HttpMethod = "Get", InsertionMode = InsertionMode.Replace})
<div id = "replaceMe"></div>
Partial View:
#model MvcApplication1.Controllers.Person
<div>
Name : #Model.Name <br />
Age : #Model.Age
</div>

When i try to execute foreach statement i am getting -Object reference not set to an instance of an object

i am working on mvc project. In my controller i am calling my stored procedure from terms class and I am returning Index page if it returns true or return terms page if it returns false.
Calling stored procedure in terms page :
public class Accept
{
public void Check()
{
using (var ctx = new termsEntities())
{
ctx.usp_ChkTerms(8, new ObjectParameter("Accepted", typeof(bool)));
ctx.SaveChanges();
}
}
}
Now i am calling this in my controller :
public ActionResult App()
{
// calling Stored procedure from Model to class
var accept = new Accept();
accept.Check();
// checking if accepted is true then return view else return another view
AppEntities Accepted = new AppEntities();
AppTerm user = new AppTerm();
AppHist history = new AppHist();
user = (from AppTerm app in Accepted.AppTerms
where app.userID == 8
select app).ToList().FirstOrDefault();
if (user != null)
{
if (user.Accepted)
{
return View("Index");
}
else
{
return View("terms");
}
}
And this is the code i am using in my terms view :
#{
ViewBag.Title = "terms";
}
<html>
<body>
<ul>
#foreach ( var item in Model)
{
<div class="Page" onclick="location.href='#Url.Action("Info", new { id = item.ID })'">
span class="Col1">
<br />
#item.ID
</span>
<span class="Title">#item.Name</span>
}
</ul>
</body>
</html>
Here when condition is true it is displaying Index page but when condition falls and when it tries to display terms page i am getting Object reference not set to an instance of an object and error is pointing to foreach loop. so what mistake i am doing here? i need help..
It is ugly, but you may try
<div class="Page" onclick='location.href="#Url.Action("Info", new { id = item.ID })"'>
<div class="Page" onclick="location.href='#Url.Action("Info", new { id = item.ID })'">
Change this to:
<div class="Page" onclick="location.href='#Url.Action('LinkText','Info', new { id = item.ID })'">
Note the quote marks around Info
edit:
Added extra argument to link.

Object reference not set to an instance of an object for dropdownlist in model

I have no idea why this is happening, I have set the values and debugged it, but it is just not passing the information from the controller to the view. Here is what is going on
Model:
public class QueueFilterModel
{
public string SelectedFilter { get; set; }
public string query { get; set; }
public List<string> MyFilterList { get; set; }
}
Controller:
[HttpGet]
public ActionResult Queue()
{
QueueFilterModel model = new QueueFilterModel()
{
SelectedFilter = "All",
query = "SELECT * FROM [CHAVI].[dbo].[TicketQueue]",
MyFilterList = new List<string>()
};
model.MyFilterList.Add("All");
model.MyFilterList.Add("Open");
model.MyFilterList.Add("Closed");
return View();
}
View:
#model RazorARPP.Models.QueueFilterModel
#{
ViewBag.Title = "Queue";
}
<h2>Queue</h2>
<form action="" method="post" enctype="multipart/form-data" id="MyForm">
Filter
<div>
Filter Options:
</div>
<div>
#Html.DropDownList("test", new SelectList(Model.MyFilterList,Model.SelectedFilter))
</div>
<h3>Insert Instructions Here</h3>
#{
var DB = Database.Open("CHAVI");
var grid = new WebGrid(DB.Query("SELECT * FROM [TicketQueue]"), null, null, 20);
#grid.GetHtml(
tableStyle: "webgrid",
columns: grid.Columns(
grid.Column(header: "Link", style: "labelcolumn", format: (item) => Html.ActionLink("Edit Item", "EditQueue", new { id = item.QueueID})),
grid.Column("Description", "Description"),
grid.Column("QueueDate", "QueueDate"),
grid.Column("Note", "Note"),
grid.Column("Status", "Status"),
grid.Column("LastUpdated", "LastUpdated")
)
)
}
</form>
The grid part is working fine (and the query). The problem is in the dropdown, it isn't set to anything there. Any thoughts? Thanks.
Are you not passing the model to view?
Should it not be
public ActionResult Queue()
{
QueueFilterModel model = new QueueFilterModel()
{
SelectedFilter = "All",
query = "SELECT * FROM [CHAVI].[dbo].[TicketQueue]",
MyFilterList = new List<string>()
};
model.MyFilterList.Add("All");
model.MyFilterList.Add("Open");
model.MyFilterList.Add("Closed");
return View(model);
}
Try using:-
public ActionResult Queue()
{
QueueFilterModel model = new QueueFilterModel()
{
SelectedFilter = "All",
query = "SELECT * FROM [CHAVI].[dbo].[TicketQueue]",
MyFilterList = new List<string>()
};
model.MyFilterList.Add("All");
model.MyFilterList.Add("Open");
model.MyFilterList.Add("Closed");
return View(model);
}

How to use a dynamic var in ActionLink to call a different controller's action

Part of ControllerA:
public ActionResult Index()
{
ViewBag.Message = "ToolScope Testing";
var Baselines = from b in db.Baselines
orderby b.Name
select b;
ViewBag.Baselines = Baselines;
return View();
}
Part of View for ControllerA
#foreach (var item in #ViewBag.Baselines)
{
<tr>
<li> #Html.ActionLink( item.Name, "Details", "BaseLine",new { id = item.BaselineID }, null) </li>
</tr>
}
The item.Name is causing problem, however, it works if I use something like
<li> #Html.ActionLink( "SomeName", "Details", "BaseLine",new { id = item.BaselineID }, null) </li>
What should I do to have the dynamic names, i.e., the first ActionLink?
P.S.: I am new to MVC
I see you are new to MVC. Good news, you've already gotten the V(iew) and the C(ontroller). Now it's time to master the M(odel). In your example, you are using the ViewBag to transport knowledge from the Controller to your View. This is a typical responsibility of the Model. So you need to create a new class in your Models directory. It will probably look something like this:
public class MyFirstModel
{
public IEnumerable<MyCustomType> Baselines { get; set; }
public MyFirstModel() { }
}
Edit your Controller
public ActionResult Index()
{
ViewBag.Message = "ToolScope Testing";
var baselines = from b in db.Baselines
orderby b.Name
select b;
var model = new MyFirstModel
{
Baselines = baselines
};
return View(model);
}
Then, add this to the top of your View:
#model MvcApplication.Models.MyFirstModel
Now you can use this code in your view instead:
#foreach (var item in Model.BaseLines)
{
<tr>
<li> #Html.ActionLink( item.Name, "Details", "BaseLine",new { id = item.BaselineID }, null) </li>
</tr>
}

Resources