Passing variable from one class to a view of a different class - asp.net-mvc

I'm having a bit of trouble passing the variable score, that is a variable in my Evaluation class, that is initialized here in my [httpPost]ifstatements(Evaluation model) method in my Quiz controller to a view belonging to a different controller of a different class. When the score is greater than zero, i.e i answer at least one question correct, I am brought to the results view and the score is shown to me. But im having trouble printing that score out in another view called Index that is part of my index method in my LEADERBOARD controller of the LEADERBOARD class
Quiz Controller
public ActionResult ifStatement()
{
var evalVM = new Evaluation();
//the below is hardcoded for DEMO. you may get the data from some
//other place and set the questions and answers
var q1 = new Question { ID = 1, QuestionText = "1. Which of the following shows the correct syntax for an if statement?" };
q1.Answers.Add(new Answer { ID = 12, AnswerText = "a. if expression" });
q1.Answers.Add(new Answer { ID = 13, AnswerText = "b. if { expression }" });
q1.Answers.Add(new Answer { ID = 14, AnswerText = "c. if ( expression ){}" });
q1.Answers.Add(new Answer { ID = 15, AnswerText = "d. expression if" });
evalVM.Questions.Add(q1);
return View(evalVM);
}
[HttpPost]
public ActionResult ifStatement(Evaluation model)
{
int score = 0;
if (ModelState.IsValid)
{
using (UsersContext db = new UsersContext())
{
foreach (var q in model.Questions)
{
var qId = q.ID;
List<string> listSelectedAnswer = new List<string>();
listSelectedAnswer.Add("14");
listSelectedAnswer.Add("19");
listSelectedAnswer.Add("22");
listSelectedAnswer.Add("25");
listSelectedAnswer.Add("28");
listSelectedAnswer.Add("33");
foreach (string answer in listSelectedAnswer)
{
foreach (var answer2 in model.Questions)
{
if (answer == answer2.SelectedAnswer)
{
score = score + 3;
}
}
}
model.Score = score;
ViewBag.score = model.Score;
if (score > 0)
{
return View("results");
}
else
{
//score = 0;
//return Content("Please check all answers have been submitted!");
return Content("Error, please ensure all questions have been answered. You may use the back button to continue the Quiz."); //PRG Pattern
}
}
}
}
model.setScore(score);
return View("ThankYou");
}
Leaderboard Controller
public class LeaderboardController : Controller
{
UsersContext db = new UsersContext();
//
// GET: /Leaderboard/
TutorialEntities t = new TutorialEntities();
Evaluation e = new Evaluation();
public ActionResult Index()
{
// Evaluation ev = new Evaluation();
// var tutorial = t.Evaluations.ToList();
//ViewBag.Scores = t.Evaluations.Select(a => a.Score).ToList();
//ViewBag.Scores = e.getScore();
//ViewBag.Score = e.getScore();
ViewBag.Users = db.UserProfiles.ToList();
ViewBag.Scores = t.Evaluations.ToList();
return View();
}
}
Index View
<h2>Leaderboard</h2>
#foreach (var item2 in ViewBag.Users)
{
<p>
Score: #ViewBag.Score
</p>
}
#foreach (var item in ViewBag.Users)
{
<p>
UserID: #item.UserId
<br />
UserName: #item.UserName
<br />
</p>
}
All that shows on the page when i go this view is the name of the people who are registered on my website and their id but score is blank! I cant seem to get my head around it i have tried numerous ways but it seems it cant see the score that is being initialised in the ifstatement method

Your controller sets viewbag.scores, however your view is trying to access viewbag.score?

Related

How to update existing rows using Entity Framework?

I have the following one to many table as below. I am experiencing issue when it comes to editing the existing rows with the following code. Please understand that I am pretty new to the ET relationship, so any detailed explanation would be greatly appreciated. Why it is returning null values?
public void UpdateReportGroup(TReportHeaderModel model)
{
if (model.THeaderTitle == null)
{
throw new Exception("Report Group Title must be filled in");
}
if (model.THeaderTitle.Length <= 0)
{
throw new Exception("A Report Group Title must be filled in.");
}
using (var connection = new TReportEntitiesConnection())
{
var header = connection.THeaders.SingleOrDefault(f => f.ID == model.ID);
var reports = connection.TReport.Where(f => f.THeaderID == model.ID);
connection.TReport.RemoveRange(reports);
foreach (var urls in model.TReports)
{
connection.TReport.Add(new TReport()
{
TReportName = urls.name,
URL = urls.url,
});
}
connection.THeaders.Add(header);
connection.SaveChanges()
}
}
Everytime, I debug it,it is giving null values for the 'TReport' table.
My create new rows works perfectly with the following code. Meaning, I am returning the correct form with correct field names.
public void CreateReport(TReportHeaderModel model)
{
if (model.THeaderTitle == null)
{
throw new Exception("Report Group Title must be filled in");
}
if (model.THeaderTitle.Length <= 0)
{
throw new Exception("A Report Group Title must be filled in.");
}
using (var connection = new TReportEntitiesConnection())
{
var header = new THeader()
{
ClientID = model.ClientID,
THeaderTitle = model.THeaderTitle,
RowNumber = model.RowNumber
};
foreach (var urls in model.TReports)
{
header.TReports.Add(new TReport()
{
TReportName = urls.name,
URL = urls.url
});
}
connection.THeaders.Add(header);
connection.SaveChanges();
}
}
As you can see, I am following DI pattern, and therefore I am calling these two methods in my controller as below:
[HttpPost]
public ActionResultModel CreateReportAPI([FromBody] TReportHeaderModel model) //attempt 3
{
try {
if (ModelState.IsValid)
{
var isValid = _tReportingService.HeadernameExists(model.THeaderTitle);
if (!isValid)
{
Console.WriteLine("it does not exist");
var user = this.GetCurrentUserAccount();
model.ClientID = user.SelectedClient.ID;
_tReportingService.CreateReport(model);
}
else //Update method comes till here and it goes //straight to the error
{
Console.WriteLine("it exists");
var user = this.GetCurrentUserAccount();
model.ClientID = user.SelectedClient.ID;
_tReportingService.UpdateReportGroup(model);
}
}
return new ActionResultModel()
{
Success=true,
Message="Report Group Successfully Saved."
};
}
I guess it would be the last time I'd posting questions here as I understood that it takes you nowhere if you just ask so I'd rather research more and keep trying it until I got it so here I am answering my own question as I'd solved it.
As the model gets generated from WebApi which is completely detached from ET, I am loading the database first and compare which children have been added, deleted & updated. Here is an example of perfect one to many relationship's update/delete.
using (var connection = new TReportEntitiesConnection())
{
var header = connection.THeaders.Include("TReports").SingleOrDefault(f => f.ID == model.ID);
if (header != null)
{
header.THeaderTitle = model.THeaderTitle; //update parent
}
foreach (var existingChild in header.TReports.ToList())
{
if (!model.TReports.Any(c => c.ID == existingChild.ID))
connection.TReport.Remove(existingChild);
}
foreach (var url in model.TReports)
{
var existingChild = header.TReports
.Where(c => c.ID == url.ID)
.SingleOrDefault();
if (existingChild != null)
{ //update child
connection.Entry(existingChild).CurrentValues.SetValues(url);
}
else
{
var newChild = new TReport
{
TReportName = url.name,
URL = url.url,
};
header.TReports.Add(newChild);
}
}
connection.SaveChanges();
}

MVC checkboxes & FormCollection

On a mass-edit form page I display about 50 objects that have some boolean properties as well. The controller receives a FormCollection with all values from the edit page.
public void _EditAll(FormCollection c)
{
int i = 0;
if (ModelState.IsValid)
{
var arrId = c.GetValues("channel.ID");
var arrName = c.GetValues("channel.displayedName");
var arrCheckbox = c.GetValues("channel.isActive");
for (i = 0; i < arrId.Count(); i++)
{
Channel chan = db.Channels.Find(Convert.ToInt32(arrId[i]));
chan.displayedName = arrName[i];
chan.isActive = Convert.ToBoolean(arrCheckbox[i]);
db.Entry(chan).State = EntityState.Modified;
}
db.SaveChanges();
}
}
Now, for checkboxes, MVC creates hidden inputs on the form (otherwise "false" could not be posted back). In the controller, when receiving the FormCollection, this leads to the case that I receive an array of say
50 IDs,
50 names and ..
71 or so values for the checkboxes,
since the hidden checkbox has the same name as the visible one.
What's a good way to handle that and get the proper value of the checkbox?
Sample for editing array of entities that have boolean field.
Entity:
public class Entity
{
public int Id { get; set; }
public bool State { get; set; }
}
Controller:
public ActionResult Index()
{
Entity[] model = new Entity[]
{
new Entity() {Id = 1, State = true},
new Entity() {Id = 2, State = false},
new Entity() {Id = 3, State = true}
};
return View(model);
}
[HttpPost]
public ActionResult Index(Entity[] entities)
{
// here you can see populated model
throw new NotImplementedException();
}
View:
#model Entity[]
#{
using (Html.BeginForm())
{
for (int i = 0; i < Model.Count(); i++ )
{
#Html.Hidden("entities[" + i + "].Id", Model[i].Id)
#Html.CheckBox("entities[" + i + "].State", Model[i].State)
}
<input type="submit"/>
}
}
The only tricky thing is html elements naming.
More info about binding arrays.
I'm converting all arrays containing checkbox-values:
"false" => "false", if not preceded by "true"

Passing query data from controller to view

I have been stuck on this problem for too long and would love some help.
On a view people can select two items from two radiobutton lists which returns via a FormMethod.Get to the Index event in HomeController.
These 2 values, 'parts and 'use' are queried to return a result and its passed back to the view via a viewbag. However the viewbag returns a line like { Item = Kona, Price = 400.0000, Quantity = 2 } in the view.
Whereas I want to return each item such as item.Item, Item.Price so I can use them individually.
I have tried everything I can find to no avail.
Anonymous classes items also throw red errors
View
foreach(var item in ViewBag.getstock)
{ //Show it and then make a new line with the <BR/>
#item < br / >
//{ Item = Kona, Price = 400.0000, Quantity = 2 }
}
HomeController
public ActionResult Index()
{
//this returns the entire query string
ViewBag.querystring = Request.QueryString;
//if any keys are in the url from the view
if (Request.QueryString.HasKeys())
{
//extract them out so that you can use them
//key = the name such as Part or Use it goes Key & Value this is passed to a Viewbag
//get(o) is getting the value at place 0, the first value in the url
ViewBag.querystringvalue0 = Request.QueryString.Get(0);
ViewBag.querystringvalue1 = Request.QueryString.Get(1);
}
//if there is any query string
if (Request.QueryString.HasKeys())
{
//pass the data to a couple of variables,
var parts = Request.QueryString.Get(0);
var use = Request.QueryString.Get(1);
//put them in a new query and return the results
ViewBag.getstock = from p in Bikeshopdb.Stocks
where p.PartName == parts && (p.Road == use || p.Mtn == use || p.Hybrid == use) select new
{
p.Item, p.Price, p.Quantity
};
}
return View(Bikeshopdb.Stocks.ToList());
Use a ViewModel class to hold the query results and pass back to the view. For example:
HomeController
public class MatchingStock()
{
public int ID { get; set; }
public string Item { get; set; }
public int Price { get; set; }
public int Quantity { get; set; }
}
public ActionResult Index()
{
//...
var list =
(from p in Bikeshopdb.Stocks
where p.PartName == parts &&
(p.Road == use || p.Mtn == use || p.Hybrid == use)
select new MatchingStock() {
ID = p.ID,
Item = p.Item,
Price = p.Price,
Quantity = p.Quantity}).ToList();
ViewBag.getstock = list;
//...
}
View
#foreach (var item in (List<MatchingStock>)ViewBag.getstock)
{
#item.Item #item.Price #item.Quantity
<br />
}

two models in a view - not working for me

I have created an entity data model from my database. however in certain areas of the application i need to pass two models. thus i create a third model which has as properties the objects of each required model.
In the scenario, i want to use one model just to show some data to the user and the other is to be populated by the user using form elements. therefore, i create a constructor in my custom model to populate it. here's the code:
THE CUSTOM MODEL
public class ordersModel
{
public ordersModel(order or)
{
this.prods = new order_products();
this.new_order = new order();
this.new_order.customer_id = or.customer_id;
this.new_order.my_id = or.my_id;
this.new_order.my_order_id = or.my_order_id;
this.new_order.order_date = or.order_date;
this.new_order.order_status_id = or.order_status_id;
}
public order new_order { get; set; }
public order_products prods { get; set; }
}
IT IS USED IN THE CONTROLLER AS FOLLOWS:
public ActionResult Create()
{
order or = new order();
// Store logged-in user's company id in Session
//or.my_id = Session["my_id"].ToString();
//do something to allow user to select customer, maybe use ajax
or.customer_id = "123";
or.order_amount = 0;
or.my_id = "74973f59-1f6c-4f4c-b013-809fa607cad5";
// display date picker to select date
or.order_date = DateTime.Now.Date;
// fetch statuses from database and show in select list box
or.order_status_id = 1;
return View(or);
}
//
// POST: /Orders/Create
[HttpPost]
public ActionResult Create(order or)
{
using (invoicrEntities db = new invoicrEntities())
{
var temp = db.last_order_number.SingleOrDefault(p => p.my_id == or.my_id);
if (temp != null)
{
or.my_order_id = temp.my_order_id + 1;
if (ModelState.IsValid)
{
ordersModel ord = new ordersModel(or);
db.orders.AddObject(or);
temp.my_order_id = temp.my_order_id + 1;
//TempData["my_order_id"] = or.my_order_id;
db.SaveChanges();
return RedirectToAction("AddProducts", ord);
//return RedirectToAction("AddProducts", new { id = or.my_order_id });
}
return View(or);
}
return RedirectToAction("someErrorPageDueToCreateOrder");
}
}
public ActionResult AddProducts()
{
using (invoicrEntities db = new invoicrEntities())
{
//string my_id = TempData["my_id"].ToString();
//string my_order_id = TempData["my_order_id"].ToString();
string my_id = "74973f59-1f6c-4f4c-b013-809fa607cad5";
int my_order_id = 1;
//Int64 my_order_id = Convert.ToInt64(RouteData.Values["order_id"]);
// Display this list in the view
var prods = db.order_products.Where(p => p.my_id == my_id).Where(p => p.my_order_id == my_order_id).ToList();
var or = db.orders.Where(p => p.my_id == my_id).Where(p => p.my_order_id == my_order_id).ToList();
if (or.Count == 1)
{
//ViewData["name"] = "sameer";
ViewData["products_in_list"] = prods;
ViewData["order"] = or[0];
return View();
}
return RedirectToAction("someErrorPageDueToAddProducts");
}
}
[HttpPost]
public ActionResult AddProducts(order_products prod)
{
prod.my_id = "74973f59-1f6c-4f4c-b013-809fa607cad5";
// find a way to get the my_order_id
prod.my_order_id = 1;
return View();
}
THIS ALL WORKS OUT WELL, UNTIL IN THE "ADDPRODUCTS" VIEW:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<invoicr.Models.ordersModel>" %>
AddProducts
<h2>AddProducts</h2>
<%: Model.new_order.my_id %>
the above statement gives an error
Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.
what am i doing wrong here?
You seem to be passing the wrong model when redisplaying your Create view.
Try passing the ord instance which is of type ordersModel and which is what your view is strongly typed to:
public ActionResult Create(order or)
{
using (invoicrEntities db = new invoicrEntities())
{
var temp = db.last_order_number.SingleOrDefault(p => p.my_id == or.my_id);
if (temp != null)
{
or.my_order_id = temp.my_order_id + 1;
ordersModel ord = new ordersModel(or);
if (ModelState.IsValid)
{
db.orders.AddObject(or);
temp.my_order_id = temp.my_order_id + 1;
db.SaveChanges();
return RedirectToAction("AddProducts", ord);
}
return View(ord);
}
return RedirectToAction("someErrorPageDueToCreateOrder");
}
}
UPDATE:
Now that you have shown your AddProducts action you are not passing any model to the view although your view expects an ordersModel instance. So don't just return View();. You need to pass an instance of ordersModel:
if (or.Count == 1)
{
ViewData["products_in_list"] = prods;
ViewData["order"] = or[0];
ordersModel ord = new ordersModel(or[0]);
return View(ord);
}

MVC C# Select Where

I am trying to add filter by ID for the following:
public ActionResult Index()
{
var model = from o in new MainDBContext().OffLinePayments
select new EditOffLinePayment
{
ID = o.ID,
Amount = o.Amount
};
return View(model);
}
What I would like to do is the following:
public ActionResult Index(long? id)
{
if (id != null)
{
var model = from o in new MainDBContext().OffLinePayments
**Where Assigned_ID == id**
select new EditOffLinePayment
{
ID = o.ID,
Amount = o.Amount
};
return View(model);
}
else
{
var model = from o in new MainDBContext().OffLinePayments
select new EditOffLinePayment
{
ID = o.ID,
Amount = o.Amount
};
return View(model);
}
}
try
var model = from o in new MainDBContext().OffLinePayments
where o.Assigned_ID == id
select new EditOffLinePayment
{
ID = o.ID,
Amount = o.Amount
};
If I understand correctly, your problem is that the compiler doesn't let you write where o.Assigned_ID == id in the query.
That's because id is a Nullable<long>, which is not implicitly convertible to a long (which OffLinePayment.Assigned_ID presumably is).
You need to write where o.Assigned_ID == id.Value instead. Take a look at what the Value property does so that you don't get any surprises.
A cleaner, shorter and much more readable syntax would look like this:
public ActionResult Index(long? id){
using (var ctx = new MainDBContext())
{
var entities = ctx.OfflinePayments.Where(e => !e.HasValue || e.Assigned_ID == id.Value);
var model = entities.Select(e => new EditOfflinePayment { ID = e.ID, Amount = e.Amount }).ToList();
return View(model);
}
}

Resources