I have 2 views, one to return all the locations belonging to a project, the other returns a json file containing the locations that used to show them on a google map.
Listing the locations works like this as the id is sent with the actionlink, but how do I send the project ID to the Map view?
public ActionResult GoogleMaps(int id)
{
return View(Project.Find(id).DeviceLocations);
}
//[AutoRefresh(DurationInSeconds = 30)]
public ActionResult Map(int id)
{
var map = Project.Find(id).DeviceLocations;
Locations l = new Locations();
l.locations = map;
return Json(l, JsonRequestBehavior.AllowGet);
}
Some people construct a model (class) specifically to handle all of the values being passed from the controller. So, your model would have a property called DeviceID, and would thus be strongly typed.
Alternately, you can use ViewData:
You can put this in your controller:
ViewData["DeviceID"] = id;
Then, in your view, you will need to cast it before you use it, like this:
(int)ViewData["DeviceID"]
Include a get, set property "project ID" in your Locations class.
Related
I am creating products from a product template. Each time a customer selects a product to view information about, the data from that product needs to get loaded. I have created a controller, model and view. The model is generated with TDS. I need to pass the item id to the [SitecoreId] from the controller. Here is the code I am using:
From the layout:
#{var id = Sitecore.Data.ID.Parse("{74A67488-8E33-47E2-86F5-25AD23FDF3D3}"); }
#Html.Sitecore().ControllerRendering("ProductOverview", "Index", new { ItemId = #id })
The controller:
public class ProductOverviewController : Controller
{
private readonly IMvcContext _mvcContext;
public ProductOverviewController(IMvcContext mvcContext)
{
_mvcContext = mvcContext;
}
// GET: ProductOverview
public ActionResult Index()
{
var itemId = string.Empty;
var rc = RenderingContext.CurrentOrNull;
if (rc != null)
{
var parms = rc.Rendering.Properties;
itemId = parms["ItemId"];
}
var dataSource = _mvcContext.GetContextItem<ProductOverviewModel> ();
return View(dataSource);
}
}
The itemId var has the correct id that I am passing from the layout (hard coded for now). From here I am at an absolute loss on how to get that into the model. I have tried dozens of suggestions from searches but the model always uses the current item (as set by GlassBase in the model itself) as opposed to the product id that contains the data for that product.
Is what I want to do even possible? Can the [SitecoreId] even be overridden?
The line where you are setting the value for dataSource using Glass Mapper is where you'll want to make your change..
Glass Mapper lets you use a number of different options to get the Item and cast to your "type" which looks to be ProductOverviewModel currently.
you can use the following for example (notice that I've used .SitecoreService.GetItem instead of .GetContextItem ):
//pass the GUID into here (you'd need to cast to a Guid first instead of ID)
var dataSource = _mvcContext.SitecoreService.GetItem<ProductOverviewModel>(guid);
//or if you wanted to get your ID as a Sitecore Item you could use
var dataSource = _mvcContext.SitecoreService.GetItem<ProductOverviewModel>(item.Paths.Path);
#Html.Partial("~/Areas/WO/Views/PartialContent/_FirstPage.cshtml", new ViewDataDictionary { { "WOID", WOID } })
In my Page i am accessing Partial view in the above way.
I need to pass WOID(view data dictionary) value from query string, For that i am using following Code
#{
var desc = Html.ViewContext.HttpContext.Request.QueryString.Get("ID");
Uri referrer = HttpContext.Current.Request.UrlReferrer;
string[] query = referrer.Query.Split('=');
int WOID = Convert.ToInt32(query[1]);
}
But the issue is this code is working in all browsers except I.E. i Need to Solve this problem.
Please help me
Instead of this you can have this value as part of you model and use that.That is the standard and recommeded way .
In your action method you can have these as parameter.Your query string value will get bind to this parameter
public ActionResult ActionMethod(int ID)
{
Model.WOID = WOID;
// Other logic
return View(Model)
}
Next step you can add this as a property to your view model or add it to ViewData dictionary and then access it in your partial view.
In my project I have a controller that allows you to create multiple letters of different types. All of these letter types are stored in the database, but each letter type has different required fields and different views.
Right now I have a route set up for the following URL: /Letters/Create/{LetterType}. I currently have this mapped to the following controller action:
public ActionResult Create(string LetterType)
{
var model = new SpecificLetterModel();
return View(model);
}
I also have a View called Create.cshtml and an EditorTemplate for my specific letter type. This all works fine right now because I have only implemented one Letter Type. Now I need to go ahead and add the rest but the way I have my action set up it is tied to the specific letter type that I implemented.
Since each Letter has its own model, its own set of validations, and its own view, what is the best way to implement these actions? Since adding new letter types requires coding for the model/validations and creating a view, does it make more sense to have individual controller actions:
public ActionResult CreateABC(ABCLetterModel model);
public ActionResult CreateXYZ(XYZLetterModel model);
Or is there a way I can have a single controller action and easily return the correct model/view?
You can do one of the following:
Have a different action method for each input. This is because the mvc framework will see the input of the action method, and use the default model binder to easily bind the properties of that type. You could then have a common private method that will do the processing, and return the view.
Assuming XYZLetterModel and ABCLetterModel are subclasses of some base model, your controller code could look like:
public class SomeController : Controller
{
private ISomeService _SomeService;
public SomeController(ISomeService someService)
{
_SomeService = someService;
}
public ViewResult CreateABC(ABCLetterModel abcLetterModel)
{
// this action method exists to allow data binding to figure out the model type easily
return PostToServiceAndReturnView(abcLetterModel);
}
public ViewResult CreateXYZ(XYZLetterModel xyzLetterModel)
{
// this action method exists to allow data binding to figure out the model type easily
return PostToServiceAndReturnView(xyzLetterModel);
}
private ViewResult PostToServiceAndReturnView(BaseLetterModel model)
{
if (ModelState.IsValid)
{
// do conversion here to service input
ServiceInput serviceInput = ToServiceInput(model);
_SomeService.Create(serviceInput);
return View("Success");
}
else
{
return View("Create", model);
}
}
}
The View code could look like:
#model BaseLetterModel
#if (Model is ABCLetterModel)
{
using (Html.BeginForm("CreateABC", "Some"))
{
#Html.EditorForModel("ABCLetter")
}
}
else if (Model is XYZLetterModel)
{
using (Html.BeginForm("CreateXYZ", "Some"))
{
#Html.EditorForModel("XYZLetter")
}
}
You would still have an editor template for each model type.
Another option is to have a custom model binder that figures out the type, based on some value in a hidden field, and then serializes it using that type.
The first approach is much more preferred because the default model binder works well out of the box, and it's a lot of maintenance to build custom model binders.
In a heavy enviroment application, we have Users, Locations, bla bla bla... and we use in many situations a call to a service where we retrieve the list of countries.
Where is the 'best practice' or 'proper way' to implement this. This method is called in several places and many objects has a List<CountryVO> property.
Specially considering using Razor views an often having to add this property to ModelViews
The solution is using DAL / BLL / SERVICE / UI[s] architecture.
Real Example:
public class User {
...
...
public List<DeliveryZoneVO> DeliveryZones {get;set;}
public User() {
...
DeliveryZones = service.GetDeliveryZones().ToList();
}
}
The class DeliveryZoneVO comes from a webservice, so one property is
int IdCountry
The class User have a list of DeliveryZoneVO as presented on the class, the 'problem' here, is since it retrieves the data from a web service, I only have the ID of the country.
When I prepare the data in the controller to send to the View:
UserModelView userMV = new UserModelView();
userMV.user = service.GetUserById(1);
ViewData.Model = userMV;
BUT, inside userMV.user, I have DeliveryZones with a list of DeliveryZoneVO objects with IdCountries.
In the view, when I do (for example) :
#DisplayFor(m => m.user.DeliveryZones)
I want to show the Country Name, only have the ID. So i need a reference somewhere.. the question lies in where should that data needs to be placed that is considered BEST PRACTICES.
Is having in all modelview (in the case of the example, the UserModelView() the property Countries with a List ?
A good thing because this kind of issues is to have a BaseController class that derived from controller, and all the other controllers you have derived from it.
in the BaseController put a static List<CountryVO> property with getter only, this way it will be initialized once and will be accessible to all of your's controllers and views(If you pass it with the ViewModel or ViewBag).
Example:
public class BaseController : Controller
{
private static List<CountryVO> _allCountries;
public static List<CountryVO> AllCountries
{
get{ return _allCountries ?? _GetCountriesFromSomeWhere();}
}
}
public class HomeController : BaseController
{
public ActionResult Index()
{
ViewBag.AllCountries = this.AllCountries;
return View();
}
}
I would create a partial view that is responsible for just rendering the country list. Then any changes to how the list is rendered is can be made in just one place. I would create a model class that encapsulates calling the service to get the countries. Assuming that the country list is fairly static you could handle caching of the information in the model class for less calls to the service and better performance. Below is an example of a method in the model that gets the country list from the server cache if it is available.
const string cacheId = "deliveryZones";
public List<DeliveryZoneVO> GetDeliveryZones()
{
List<DeliveryZoneVO> deliveryZones = (List<DeliveryZoneVO>)HttpRuntime.Cache.Get(cacheId);
if (deliveryZones == null)
{
deliveryZones = service.GetDeliveryZones().ToList();
System.Web.HttpContext.Current.Cache.Insert(cacheId, deliveryZones);
}
return deliveryZones;
}
First post time,
I've been playing around with MVC abit... I have a view which has multiple input fields, some of these fields can be blank on post.
The action method inside the controller for the post looks something like this
public ActionResult Filter(int? id, string firstName, string lastName, bool? isMember)
I've been using the DynamicQuery extension which has been kicking around in order to perform dynamic Linq querys on my database and I've encapsulated this in a Search object which is passed to the data access layer for execusion.
However, I also have a customized ViewData object which is passed back to the view for displaying the input values and the results of the query.
It all looks a little nasty in code as I'm having to set both the Search object properties AND the ViewDatas.
public ActionResult Filter(int? id, string firstName, string lastName, bool? isMember) {
var search = new Search {
Id = id,
FirstName = firstName,
LastName = lastName,
Member = isMember
};
var memberViewData = new MemberViewData {
Id = id,
FirstName = firstName,
LastName = lastName,
Member = isMember
};
memberViewData.Results = _dataRepository.GetMember(search);
return View("Search", memberViewData);
}
Am I over thinking this and really should just pass the values to the data access layer and populate the ViewData in the controller, or is there a much more elegant pattern or practise I could use?
Sorry if this seems dump, not allot of people to bounce ideas off and time to dig into the framework.
Use modelbinder to bind data
According to your snippet MemberViewData class has the Results property in addition to properties of Search class. So first step would be to make MemberViewData derive from Search and define a constructor that accepts Search instance as parameter and assigns it's basic properties from it. Next I would change the action method like so:
public ActionResult Filter(Search search)
{
return View("Search", new MemberViewData(search)
{
Results = _dataRepository.GetMember(search)
});
}
Like Tadeusz mentioned, a ModelBinder can help build the MemberViewData for you, which would leave only the results to be fetched.
You could also decide on creating a presentation service that understands how to build this view data object and simply delegate to it. I'd prefer the model binder approach here though.