Populate Viewmodel inside an IF statement? - asp.net-mvc

Im trying to populate a viewmodel based on the value from the querystring. Heres my controller:
public ViewResult Index(int? ShiftStatusID)
{
//Get logged in User
User user = _accountService.GetUser(_formsAuthService.GetLoggedInUserID());
if (ShiftStatusID == null) // Get all shifts
{
ViewModelShiftList viewModel = new ViewModelShiftList
{
Shifts = _shiftService.GetShifts(user.organisationID.Value).ToList()
};
}
else // Get shifts by status id
{
ViewModelShiftList viewModel = new ViewModelShiftList
{
Shifts = _shiftService.GetShiftsByStatus(user.organisationID.Value, ShiftStatusID).ToList()
};
}
return View(viewModel);
}
So it wont let me return the viewmodel to the view, saying "viewmodel does not exist in the current context". It wont let me declare the view model outside the if statement. How should this be done?

Try to move out if statement in your viewresult.
Here is a code example which should be working fine:
public ViewResult Index(int? ShiftStatusID)
{
//Get logged in User
User user = _accountService.GetUser(_formsAuthService.GetLoggedInUserID());
var viewModel = new ViewModelShiftList();
if (ShiftStatusID.HasValue)// Get shifts by status id
{
viewModel.Shifts = _shiftService.GetShifts(user.organisationID.Value).ToList();
}
else // Get all shifts
{
viewModel.Shifts = _shiftService.GetShiftsByStatus(user.organisationID.Value, ShiftStatusID).ToList();
}
return View(viewModel);
}

Clean up your code, remove duplicate lines:
public ViewResult Index(int? ShiftStatusID)
{
//Get logged in User
User user = _accountService.GetUser(_formsAuthService.GetLoggedInUserID());
List<Shift> shifts;
if(ShiftStatusID == null)
shifts = _shiftService.GetShifts(user.organisationID.Value).ToList();
else
shifts = _shiftService.GetShiftsByStatus(user.organisationID.Value, ShiftStatusID).ToList();
var viewModel = new ViewModelShiftList
{
Shifts = shifts
};
return View(viewModel);
}

Related

Display ads on multiple Views by using single controller method in MVC

I want to display different ads on multiple Views from single method. Currently, I have created separate controller method for the ads and then passing page name by using session from each View's controller method. I want to get rid off any code related to ads from each controller method.
Please suggest me way to do this.
Home controller
public ActionResult Index()
{
ClsHomeContent model = new ClsHomeContent();
List<Advertisement> advertList = new List<Advertisement>();
var context = new ApplicationDbContext();
var advert = context.Advertisement.ToList();
var pageName = context.Advertisement.Where(x => x.Page == "Home").Select(y => y.Page).FirstOrDefault();
Session["PageName"] = pageName;
return View(model);
}
HorseTracker Controller
public ActionResult HorseTracker()
{
List<Advertisement> advertList = new List<Advertisement>();
var advert = context.Advertisement.ToList();
var pageName = context.Advertisement.Where(x => x.Page == "HorseTracker").Select(y => y.Page).FirstOrDefault();
Session["PageName"] = pageName;
return View(model);
}
Then using this session value
public ClsAdvertisment advertPosition()
{
List<Advertisement> advertList = new List<Advertisement>();
ClsAdvertisment model = new ClsAdvertisment();
var context = new ApplicationDbContext();
var advert = context.Advertisement.ToList();
foreach (var advertisementData in advert)
{
if (advertisementData.Position == Session["PageName"] + "_Top_Left" || advertisementData.Position == Session["PageName"] + "_Top_Right" || advertisementData.Position == Session["PageName"] + "_Middle" || advertisementData.Position == Session["PageName"] + "_Left")
{
advertList.Add(new Advertisement()
{
AdvertId = advertisementData.AdvertId,
Position = advertisementData.Position,
FilePath = advertisementData.FilePath,
Hemisphere = advertisementData.Hemisphere,
Link = advertisementData.Link,
Title = advertisementData.Title
});
}
}
model.advertisement = advertList;
return model;
}
[ChildActionOnly]
public PartialViewResult Advertisement()
{
var model= advertPosition();
return PartialView("_pAdvertisement", model);
}
Created separate partial view
foreach (var item in Model.advertisement)
{
if (#item.Hemisphere == 1 && item.Position == (string)Session["PageName"]+"_Top_Left")
{
<a href="#item.Link" title="#item.Title" target="_blank">
#Html.Image(item.FilePath, "Image", "", "")
</a>
}
}
You can get the name of the parent controller and action methods in the child method using the ParentActionViewContext property of ControllerContext
[ChildActionOnly]
public PartialViewResult Advertisement()
{
ViewContext context = ControllerContext.ParentActionViewContext;
string controllerName = context.RouteData.Values["controller"].ToString();
string actionName = context.RouteData.Values["action"].ToString();
ClsAdvertisment model = advertPosition(controllerName, actionName);
return PartialView("_pAdvertisement", model);
}
Then modify your advertPosition() to
public ClsAdvertisment advertPosition(string controllerName, string actionName)
and within that method, select the ads to be displayed based on those values, and there is also no need to use Session.

How to redirect view in separate target window

I am using visual studio 2012 and mvc4.
I want to open CertDet view in separate window
In index view I have used submit with post method.
My Controller -
[HttpPost]
[AllowAnonymous]
public ActionResult Index(ModelCertificate cert)
{
if (ModelState.IsValid)
{
dbRTCEntities objCon = new dbRTCEntities();
Mst_Catref data = objCon.Mst_Catref.Where(x => x.Catref == cert.Catref).FirstOrDefault();
if (data != null)
{
return RedirectToAction("CertDet", new { catref = data.Catref, Excise = cert.ExciseNumber, customerNm = cert.CustomerName });
}
else
ModelState.AddModelError("", "Catref not found");
}
return View();
}
public ActionResult CertDet(string catref, string Excise, string customerNm)
{
dbRTCEntities objCon = new dbRTCEntities();
Mst_Catref data = objCon.Mst_Catref.Where(x => x.Catref == catref).FirstOrDefault();
ModelCertificate cert = new ModelCertificate();
return View(cert);
}
You should need something like this on your View:
#Html.ActionLink("CertDet", "CertDet", new { catref = data.Catref, Excise = cert.ExciseNumber, customerNm = cert.CustomerName }, new {target = "_blank"})
This will render something like this in a new window;
CertDet

The neat and simple way for multiple models in a view

What can be simplest way for having rendered in a view information from multiple models. I use ViewModel in some scenarios (in particular when models are not related directly), but now I want to made a kind of dashboard for the current user. So apart from AspNetUsers model I have for example several models (e.g. Orders, OperationJournal, Jobs etc.) that in terms of entity have each a foreign key on UserID.
I made a ViewModel such:
namespace JobShop.Models
{
class QuickProfileVM
{
public IEnumerable<Jobs> Jobs { get; set; }
public IEnumerable<AspNetUsers> AspNetUsers { get; set; }
public IEnumerable<CreditJournal> CreditJournal { get; set; }
public IEnumerable<CandidateReview> CandidateReview { get; set; }
}
}
(since the base models that I need, are done by EF they have all about relations between entities) but it seems to me that is not enough. I am not able to view both the current user profile (so one record) and it's details (more than one record and more than one model).
I have try with Partial View, both with own controller or with actions in Dashboard View controller.
As an example an ActionResult that now I play with:
public ActionResult QuickProfile()
{
var QuickProfile = new QuickProfileVM();
var AspNetUsers = new AspNetUsers();
if (User.Identity.IsAuthenticated)
{
var CurrentUser = User.Identity.GetUserId();//UserManager.FindById(User.Identity.GetUserId());
var TheUser = db.AspNetUsers.Where(u => u.Id == CurrentUser)
.Select(u => new
{
ID = u.Id,
Email = u.Email,
PhoneNumber = u.PhoneNumber,
Companyname = u.Companyname,
Address = u.Address,
ZIP = u.ZIP,
City = u.City,
Country = u.Country,
Website = u.Website,
Facebook = u.Facebook,
Twitter = u.Twitter,
GooglePlus = u.GooglePlus,
Dribble = u.Dribble,
BirthDate = u.BirthDate,
Username = u.UserName,
Surrname = u.Surname,
Name = u.Name,
Role = u.Role,
ThumbURL = u.ThumbURL,
CreditBalance = u.CreditBalance
}).Single();
var TheJournal = db.CreditJournal.Where(tj => tj.UseBy == CurrentUser)
.Select(tj => new
{
IdJournal = tj.IdJournal,
Operation = tj.Operation,
CvID = tj.CvID,
JobID = tj.JobID,
CreditConsumed = tj.CreditConsumed,
UseDate = tj.UseDate,
UseBy = tj.UseBy
}).ToList();
//similar for Jobs and CandidateReview
//
var UserId = TheUser.ID;
var username = TheUser.Username;
var role = TheUser.Role;
var InitialCredit = TheUser.CreditBalance;
AspNetUsers.UserName = TheUser.Username;
AspNetUsers.Companyname = TheUser.Companyname;
AspNetUsers.Surname = TheUser.Surrname;
AspNetUsers.Name = TheUser.Name;
AspNetUsers.ThumbURL = TheUser.ThumbURL;
AspNetUsers.CreditBalance = InitialCredit;
//I put this to ilustrates what I have accesible for example
//about CreditJournal: only methods, not properties
QuickProfile.CreditJournal.AsEnumerable();
var id = CurrentUser;
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
AspNetUsers aspNetUsers = db.AspNetUsers.Find(id);
if (aspNetUsers == null)
{
return HttpNotFound();
}
}
return View(AspNetUsers);
//Disbled since at this stage is not usefull
//return View(QuickProfile);
//return View();
}
I suggest you consider using Html.RenderAction in your view. For example, say your main dashboard is this:
#{
ViewBag.Title = "title";
}
<h2>Multiple Models</h2>
#{ Html.RenderAction("GetData", "Foo"); }
You can use Html.RenderAction to call FooController.GetData()
public class FooController : Controller
{
public ActionResult GetData()
{
var viewModel = new FooViewModel();
viewModel.TimeStamp = DateTime.UtcNow;
return View(viewModel);
}
}
So rather than having one viewmodel with lots of other viewmodels attached as properties, you can split up the rendering of the dashboard view.
Overall this should makes things easier for you - I've used this approach in the past and have found it reduces complexity.

Edit & Delete object with ViewModel

I've successfully implemented a viewmodel so I can create and return items from my database using two tables. My issue is editing and deleting individual items.
I was able to edit/delete when I was using just one table, but with two, i've run into a snag.
My view uses a viewmodel now. I am not able to figure out how to pass the specific object id when Passing an id and TransactionViewModel Viewmodel into my Edit method Parameters.
Here is my old Edit and Edit post.
public ActionResult Edit(int id = 0)
{
Transactions transactions = _db.Transactions.Find(id);
if (transactions == null)
{
return HttpNotFound();
}
return View(transactions);
}
[HttpPost]
//[ValidateAntiForgeryToken]
public ActionResult Edit(TransactionViewModel viewModel)
{
var transactionType = viewModel.Transaction.TransactionType;
if (ModelState.IsValid)
{
//If the transaction category is an Expense, set it to a negative so we can calculate later.
if (transactionType == Classes.Constants.Expense || (transactionType == Classes.Constants.Payment && viewModel.Transaction.Amount < 0))
{
viewModel.Transaction.Amount *= -1;
}
var transaction = new Transactions()
{
ClientId = viewModel.Transaction.ClientId,
Amount = viewModel.Transaction.Amount,
Date = viewModel.Transaction.Date,
Category = viewModel.Transaction.Category,
Description = viewModel.Transaction.Description,
TransactionType = viewModel.Transaction.TransactionType
};
_db.Entry(transaction).State = EntityState.Modified;
_db.SaveChanges();
return RedirectToAction("Index");
}
return View(viewModel);
}
I've tried this for my get Edit, but it returns the same thing each time and not the one specified on my view. Ex. If click edit for Client D, it will pull up the edit screen for Client A and I cannot save it. I have an edit and delete button in my viewable table next to each transaction using an #Html.ActionLink().
public ActionResult Edit(TransactionViewModel viewModel)
{
if (ModelState.IsValid)
{
var transactions = from t in _db.Transactions
join c in _db.Clients
on t.ClientId equals c.ClientId
select new TransactionViewModel() { Clients = c, Transaction = t };
return View(transactions.FirstOrDefault());
}
return RedirectToAction("Index");
}
Any help would be appreciated. Thanks!
I bet that view is being cached. There are many different ways to influence caching in the controller. If you want to simply remove cacheing, in your case for editing, then decorate that action with the following:
[OutputCache(NoStore = true, Duration = 0)]
public ActionResult Edit(TransactionViewModel viewModel)
[OutputCache(NoStore = true, Duration = 0)]
public ActionResult Edit(int id = 0)
Note: You will have to clear cache to get the new view with the no cache set above.
Your Get Edit method should still accept an int ID to select the correct record form the database and it should return the view model.
something like this:
public ActionResult Edit(int id = 0)
{
var transactions = from t in _db.Transactions
join c in _db.Clients
on t.ClientId equals c.ClientId
where t.id == id
select new TransactionViewModel() { Clients = c, Transaction = t };
return View(transactions.FirstOrDefault());
}

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);
}

Resources