So i have this aps.net mvc project in which i created a service layer, model views, controller, and a view page. But i am having trouble displaying my results to the view page. I am starting this would by passing in a specific linq statement in the service layer so i should be able to return it to show up on the view. Here is what i have:
Service:
public IEnumerable<RoleUser> GetUsers(int sectionID)
{
var _role = DataConnection.GetRole<RoleUser>(9, r => new RoleUser
{
Name = RoleColumnMap.Name(r),
Email = RoleColumnMap.Email(r)
}, resultsPerPage: 20, pageNumber: 1);
return _role;
}
Models:
public partial class Role
{
public RoleView()
{
this.Users = new HashSet<RoleUser>();
}
public ICollection<RoleUser> Users { get; set; }
}
public class RoleUser
{
public string Name { get; set; }
public string Email { get; set; }
}
Controller:
public ActionResult RoleUser(RoleView rvw)
{
var rosterUser = new RosterService().GetUsers();
ViewBag.RosterUsers = rosterUser;
return View();
}
View:
<div>
<span>#Model.Name</span>
</div>
I am not sure what i am missing or doing wrong but any tips will be great. I basically want to return the results from the linq statement i am testing to see that the connection is correct and functionality is there before enhancing. Thanks...
Well, if I were to go off the code you've provided I would say that I'm unsure how this compiles:
public partial class Role
{
public RoleView()
{
this.Users = new HashSet<RoleUser>();
}
public ICollection<RoleUser> Users { get; set; }
}
it feels like that should be:
public partial class RoleView
and then I would say that at the top of your view you're missing this:
#model NamespaceToClass.RoleView
and then I would say you're not going to be able to issue this:
#Model.Name
because RoleUser isn't your model. You're going to need to loop through the users:
#foreach (RoleUser ru in Model.Users)
and then inside that loop you can build some HTML with this:
ru.Name
but I would also question your controller. Right now it's receiving a model to return that model. There is some code missing here but generally speaking, inside the method:
public ActionResult RoleUser(RoleView rvw)
you would actually go get the data, construct the model, and then return that:
var users = serviceLayer.GetUsers(...);
// now construct the RoleView model
var model = ...
return View(model);
Based off of our conversation you currently have something like this in your controller:
public ActionResult View(int id)
{
// get the menu from the cache, by Id
ViewBag.SideBarMenu = SideMenuManager.GetRootMenu(id);
return View();
}
public ActionResult RoleUser(RoleView rvw)
{
var rosterUser = new RosterService().GetUsers();
ViewBag.RosterUsers = rosterUser;
return View();
}
but that really needs to look like this:
public ActionResult View(int id)
{
// get the menu from the cache, by Id
ViewBag.SideBarMenu = SideMenuManager.GetRootMenu(id);
var rosterUser = new RosterService().GetUsers();
ViewBag.RosterUsers = rosterUser;
return View();
}
because you're launching this page from the sidebar which is hitting this action because you're passing the id in the URL. You don't even need the other action.
Related
I have below controllers:
// GET: /MaterialPaymentRequestSbuItem/CreateChild
public ActionResult CreateChild(int? parentId)
{
if (parentId==null)
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
var parenetRequest = (from request in db.MaterialPaymentRequests
where request.Id==(int)parentId
select request);
ViewBag.MaterialPaymentRequestId = new SelectList(parenetRequest, "Id", "Description", (int)parentId);
ViewBag.ParentID = parentId;
if (parenetRequest!=null && parenetRequest.First()!=null)
ViewBag.ParentTitle = parenetRequest.First().Description;
return View();
}
// POST: /MaterialPaymentRequestSbuItem/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreateChild([Bind(Include = "Id,Name,Unit,UnitPrice,MaterialPaymentRequestId,Quantity")] MaterialPaymentRequestSubItem materialpaymentrequestsubitem)
{
if (ModelState.IsValid)
{
try
{
db.MaterialPaymentRequestSubItems.Add(materialpaymentrequestsubitem);
db.SaveChanges();
}
catch (Exception e)
{
return new HttpStatusCodeResult(HttpStatusCode.InternalServerError);
}
updateTotalPriceOfParentPaymentRequest(db, db.MaterialPaymentRequests.Find(materialpaymentrequestsubitem.MaterialPaymentRequestId));
return RedirectToAction("List", new { id = materialpaymentrequestsubitem.MaterialPaymentRequestId });
}
ViewBag.MaterialPaymentRequestId = new SelectList(db.PaymentRequests, "Id", "Description", materialpaymentrequestsubitem.MaterialPaymentRequestId);
//need to becheked
ViewBag.ParentID = materialpaymentrequestsubitem.MaterialPaymentRequestId;
if (Request != null && Request["parentID"] != null)
{
try
{
int id = Int32.Parse(Request["parentID"]);
ViewBag.ParentTitle = db.MaterialPaymentRequests.Find(id).Description;
}
catch(Exception e)
{
}
}
return View(materialpaymentrequestsubitem);
}
My main problem is that user is allowed to select model.MaterialPaymentRequestId from drop-down and he/she may leave it with no value selected. MaterialPaymentRequestId is used in first controller (befor post) to find Parent title from db and pass it to view using ViewBag, however if user does not select MaterialPaymentRequestId dropdown items, after postback, I lost MaterialPaymentRequestId. Currently I read Request variable and look inside url to find parameters to lookup for parentID.
My url calls are like http://localhost:46813/Admin/MaterialPaymentRequestSbuItem/CreateChild?parentId=23.
However this practice seems like a bad practice than I cannot pass v variable between two controller methods a process like this:
Controller method(get) ---> View ---> Controller method(post)
Currently I feel a bit stuck in MVC!
i hope i got your point right, you can use an #Html.hiddenfor(model => model.ParentId) in your view it will store ParentId value from query string and when user submits form will be posted to POST method so you dont need to look into url to get it. use a viewmodel with ParentId property and do as below
public class MaterialPaymentsViewModel {
//other properties
public int ParentId {get;set;}
}
public ActionResult CreateChild(int? parentId)
{
var model = new MaterialPaymentsViewModel{ParentId = parentId};
//other stuff
return View(model);
}
//View
#using (Html.beginform()){
//
#html.hiddenfor(m => m.ParentId)
//submit
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreateChild(MaterialPaymentsViewModel model)
{
if(model.ParentId != null)
{
//
}
//
}
[HttpPost]
public ActionResult AddToCart(int phoneListingID, string sellerSKU)
{
ShoppingBasket shoppingBasket = new ShoppingBasket();
BasketItem currentItem = new BasketItem
{
sellerID = 1,
Price = 100,
Quantity = 1,
sellerSKU = "testsku"
};
shoppingBasket.AddtoBasket(currentItem, this.HttpContext);
var viewModel = new BasketViewModel
{
basketItems = ShoppingBasket.GetBasketItems(this.HttpContext),
basketTotal = ShoppingBasket.GetBasketTotal(this.HttpContext)
};
return View(viewModel);
}
My form:
#using (Html.BeginForm("AddToCart","ShoppingBasket",new { phoneListingID = 12345, sellerSKU = "test"}, FormMethod.Post ))
{
<input type="submit" value="AddToCart" />
}
The expected result is that my BasketViewModel page is returned, however the view being returned is ShoppingBasket/AddToCart?PhoneID=xxxx&sellerSKU=xxxx
What am I doing wrong?
In MVC Suppose your action is like
public ActionResult MyAction()
{
return View();
}
In this scenerio it will point to the view named 'MyAction'. If you want to send it to another view make it like
public ActionResult MyAction()
{
return View("MyViewName");
}
If you want to pass some model to make it like
public ActionResult MyAction()
{
return View("MyViewName",model); // Here model is your object of model class
}
In you snippet your are returning default i.e. 'AddToCart' view because you are not describing explicitly. Make your code like
return View("BasketViewModel",viewModel); // where BasketViewModel is your view name
You're returning that controller's View, if you wish to transfer to another view try
return BasketViewActionResult(viewmodel)
Then access your 'BasketViewActionResult'
Function BasketViewActionResult(model as BasketViewModel) as ActionResult
return View(model)
End Function
Sorry if you don't get VB, I can translate it to C# for you if you wish.
Edit:
You can also simply change the form's action.
#using (Html.BeginForm("BasketView","ShoppingBasket",...
and make all your manipulations within that actionresult
I have a table of students and i wanted to show the name of the student on the profile page which is stored in the students table.
This is what i have in mind for my controller:
public ActionResult StudentName(StudentModel model)
{
if(ModelState.IsValid)
{
using (var db = new SchoolDataContext())
{
var result = from s in db.Students select s.StudentName;
model.StudentName = result.ToString();
}
}
}
in my view i have:
#Html.LabelFor(s => s.StudentName)
#Html.TextBoxFor(s => s.StudentName)
my model:
public class StudentModel
{
[Display(Name = "Student Name")]
public string StudentName{ get; set; }
}
I will need a get method to get the student name to display in the textbox and at the same time have a post method so that it could be saved if changed within the same box after clicking save.
Probably your controller would look something like this:
public ActionResult StudentName(int studentId)//you can't pass a model object to a get request
{
var model = new StudentModel();
using (var db = new SchoolDataContext())
{
//fetch your record based on id param here. This is just a sample...
var result = from s in db.Students
where s.id equals studentId
select s.StudentName.FirstOrDefault();
model.StudentName = result.ToString();
}
return View(model);
}
In the get above, you can pass in an id and then fetch the record from the database. Populate your model properties with the data retrieved and pass that model into your view.
Then in the post action below, you accept the model as an argument, check the model state, and process the data. I'm showing a redirect here, but you can return any view you'd like after the post executes.
[HttpPost]
public ActionResult StudentName(StudentModel model)
{
if(ModelState.IsValid)
{
using (var db = new SchoolDataContext())
{
//update your db record
}
return RedirectToAction("Index");
}
return View(model);
}
Problem is:
I am using a textbox to get a string q and want to pass it to 3 different actions in search controller. i.e. action1(string q), action2(string q) and so on
Now syntax of my action:
public ActionResult action1(string q)
{
var mydata = from p in fab //LINQ logic
select new action1class
{ data1=p //assignment };
return View("_partialAction1", mydata);
}
Similarly there are two other actions.
I am using 3 different actions because my LINQ logic gets data from 3 different sources so there different mydata needs to be created.
My problem is: I am trying that when I click on 'search' Button of textbox then all the 3 actions should run and generate partial view one below other in some <div id="action1"> tags.
I tried to use ajax.BeginForm but it can only call one action at a time
#using (Ajax.BeginForm("action1", "Search", new AjaxOptions
{
HttpMethod = "GET",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "action1",
LoadingElementId="progress"
}))
Also I tried to use ViewModel but the problem is that I was unable to pass a bigger model to the view along with these mydata kind of data obtained in LINQ's in the action. I have no clear idea of how to use viewmodel in this case.
Is the approach that I am using correct? Or can there be any other way? I want to show result of all actions with button click.
There are two types of actions are in MVC framework. The first ones are the main actions and they are invoked from the browser one at a time. The second type are called as Child Actions and these actions can't be invoked from the browser but from the views returned by the main actions. Multiple child actions can be called under a main action. So you have to look into child actions whether they help or not.
Ex.
// main action that returns a view
public ViewResult Index()
{
var model = ...
return View(model);
}
// couple of child actions each returns a partial view
// which will be called from the index view
[ChildActionOnly]
public PartialViewResult ChildAction1()
{
var model = ...
return PartialView(model);
}
[ChildActionOnly]
public PartialViewResult ChildAction2()
{
var model = ...
return PartialView(model);
}
// index view
Index.cshtml
#model ...
#Html.Action("ChildAction1");
#Html.Action("ChildAction2");
...
http://msdn.microsoft.com/en-us/library/ee839451.aspx
You can only have one action per request. If you want to have 3 different partial views for a singular click, you will need to construct a layout page that includes the 3 partial views how you want them and make sure that your action receives the proper parameters to perform all of the partial view rendering.
Why not pass the ViewModel to the partialViews. Make sure you have different properties in the ViewModel to hold the PartialView Specific data plus the search text. Here is an example:
Model
public class Product
{
public string Name { get; set; }
public string Type { get; set; }
public string Class { get; set; }
}
ViewModel
public class ProductSearch
{
public ProductSearch()
{
q = string.Empty;
Product1 = new Product();
Product2 = new Product();
}
public string q { get; set; }
public Product Product1 { get; set; }
public Product Product2 { get; set; }
}
_Partial1.cshtml
#model Test1.Models.ProductSearch
<div>Product1</div>
#Html.TextBoxFor(a => a.Product1.Name)
_Partial2.cshtml
#model Test1.Models.ProductSearch
<div>Product2</div>
#Html.TextBoxFor(a => a.Product2.Name)
ActualView.cshtml
#model Test1.Models.ProductSearch
#{
ViewBag.Title = "ActualView";
}
<h2>ActualView</h2>
#using (Html.BeginForm())
{
#:SearchText
#Html.TextBoxFor(m => m.q)
Html.RenderAction("_Partial1", Model);
Html.RenderAction("_Partial2", Model);
<input type="submit" runat="server" id="btnSubmit" />
}
Temp Data (you will be getting it from DB/ any other source)
private List<Product> ProductsToSearch()
{
return new List<Product>() { new Product() { Name = "Product One", Class = "A", Type = "High" }, new Product() { Name = "Product Two", Class = "A", Type = "Low" }, new Product() { Name = "Product Three", Class = "B", Type = "High" } };
}
Controller Actions
public ActionResult _Partial1(ProductSearch search)
{
Product Product1 = ProductsToSearch().Where(a => a.Class.Equals(search.q) && a.Type.Equals("High")).SingleOrDefault();
search.Product1 = Product1;
return PartialView(search);
}
public ActionResult _Partial2(ProductSearch search)
{
Product Product2 = ProductsToSearch().Where(a => a.Class.Equals(search.q) && a.Type.Equals("Low")).SingleOrDefault();
search.Product2 = Product2;
return PartialView(search);
}
[HttpPost]
public ActionResult ActualView(ProductSearch search)
{
return View(search);
}
public ActionResult ActualView()
{
ProductSearch search = new ProductSearch();
return View(search);
}
Now if you enter 'A' for SearchText and hit Submit Query you will get two different results (basically common search text is used and based on the search query in each partial view it has generated different results)
I have two controllers
BloggsController:
//Last blogg from the database
public ActionResult LastBlogg()
{
var lastblogg = db.Bloggs.OrderByDescending(o => o.ID).Take(1);
return View(lastblogg);
}
DishesController:
//Last recipe from the database
public ActionResult LastRecipe()
{
var last = db.Dishes.OrderByDescending(o => o.ID).Take(1);
return View(last);
}
I want to show the result of this on my start-page, Views/Home/index.
If I put this in my HomeController:
//Last recipe from the database
public ActionResult Index()
{
var last = db.Dishes.OrderByDescending(o => o.ID).Take(1);
return View(last);
}
Can I show the result in of recipe on my start-page but how do I show both the result of the blogg and recipe on om startpage?
You should create separate partial views for LastBlogg and LastRecipe and place both of them to your home page (new Model will be required).
Create a View Model and add both Blogg and Recipe to it.
public ActionResult Index()
{
var lastRecipe = db.Dishes.OrderByDescending(o => o.ID).Take(1);
var lastblogg = db.Bloggs.OrderByDescending(o => o.ID).Take(1);
var model = new BloggRecipeModel(lastRecipe, lastblogg);
return View(model);
}
You could simply create a custom ViewData in your Models folder, like this:
public class MyCustomViewData
{
public Dish Dish {get;set;}
public Blog Blog {get;set;}
}
Then in your controller:
ViewData.Model = new MyCustomViewData
{
Dish = db.Dishes.OrderByDescending(o => o.ID).Take(1);
Blog = db.Bloggs.OrderByDescending(o => o.ID).Take(1);
}
return View();
And in your view, set the #Model property to Models.MyCustomViewData and handle it accordingly.