How To Switch _Layout view in MVC5 - css

I Have a Table that contains different color of themes and I have define the _Layouts and css,
I have apply the css to the their respectful layout.
e.g
_LayoutBlue
_LayoutGreen
I want to Check using a switch statement that when a user logins before rendering the view it should check the theme colour ID the user Choosed while creating an account and Apply to the User View
the question is, Is it Possible for me to do that from the Login controller so as to control the rendering layout based on the user theme colour in the database table
e.g is
switch(ThemeID)
{
case 1:
Layout = "~/Views/Shared/_BlueLayout.cshtml";
break;
case 2:
Layout = "~/Views/Shared/_MagentaLayout.cshtml";
break;
default:
Layout = "~/Views/Shared/_Layout.cshtml";
break;
}

Yes the way you showed in your question ,we can do like that also ,other easy and effective way is :
We can override the default layout rendering by returning the layout from the ActionResult by using the below code:
public ActionResult Index()
{
RegisterModel model = new RegisterModel();
var layout="";
//Just check your conditions here instead in view and return a appropriate layout from here
layout="~/Views/Shared/_BlueLayout.cshtml";
return View("Index", layout , model);
}
OR Instead of applying condition in View just put conditions in Controller instead as :
Controller :
public ActionResult Index()
{
RegisterModel model = new RegisterModel();
//Just check your conditions here instead in view and put appropriate layout in Viewbag from here
Viewbag.layout="~/Views/Shared/_BlueLayout.cshtml";
return View("Index", model);
}
View :
#{
Layout = Viewbag.layout;
}

Related

Sitecore MVC redirect to another page

I had a requirement in my Sitecore MVC to display Carousel Items in the Homepage and when click the View More it will redirect to another page for user to view the full content
How could I achieve this? Currently all my items in Sitecore has Controller Rendering in Presentation Details. I'm just not sure how to get the GUID of the Carousel Item using then in the controller action it will redirect on the page?
I assume that you have carousel items under one folder in your content tree in Sitecore with some specific fields for each carousel item like image, title ...etc, so you should have field in the carousel items with for link:
Name: Link Type : GeneralLink
link each carousel item to the proper page ,And then in your view you can read the page URL:
and you can use this method to get link URL to the page from your carousel component :
public String LinkUrl(Sitecore.Data.Fields.LinkField lf)
{
switch (lf.LinkType.ToLower())
{
case "internal":
// Use LinkMananger for internal links, if link is not empty
return lf.TargetItem != null ? Sitecore.Links.LinkManager.GetItemUrl(lf.TargetItem) : string.Empty;
case "media":
// Use MediaManager for media links, if link is not empty
return lf.TargetItem != null ? Sitecore.Resources.Media.MediaManager.GetMediaUrl(lf.TargetItem) : string.Empty;
case "external":
// Just return external links
return lf.Url;
case "anchor":
// Prefix anchor link with # if link if not empty
return !string.IsNullOrEmpty(lf.Anchor) ? "#" + lf.Anchor : string.Empty;
case "mailto":
// Just return mailto link
return lf.Url;
case "javascript":
// Just return javascript
return lf.Url;
default:
// Just please the compiler, this
// condition will never be met
return lf.Url;
}
}
and in your carousel view :
Sitecore.Data.Fields.LinkField linkField = carouselItem.Fields["Link"];
var pageUrl = linkField.LinkUrl();
This code is taken from this answer
I think you need to prepare appropriate model object in the controller action and then pass it to the view.
Model class:
public class CarouselModel
{
public List<Item> CarouselItems { get; set; }
}
Controller action:
public ActionResult Carousel()
{
var model = new CarouselModel
{
CarouselItems = /* get appropriate items dependent on your logic */
};
return View("~/Views/renderings/Carousel.cshtml", model);
}
Razor view:
#model CarouselModel
<div>
#foreach(var carouselItem in Model.CarouselItems)
{
Sitecore.Data.Fields.LinkField targetLinkField = carouselItem.Fields["Target"];
Some link
}
</div>
Example above assumes that template of 'Carousel Item' contains 'Target' link field.

ASP.Net MVC Authentication - Hide Element in View based on roles

Is there a possibility to hand over the Result of the Authorize-Attribute to the View?
Let's assume I want to hide 5 links in my Index view based on the memberships of a User.
[Authorize(Roles = "Admin")]
public ActionResult Index(){
....
}
The code above will prevent all users that are not part of the Admin-Group from visiting the Index page.
#{
if(User.IsInRole("Admin"){
Some link to be hidden
}
}
This code will hide the link if the User is not part of the Admin role. This is basically what I want BUT using this method I have to change the role name on every hidden link if the role would change.
Isn't there something like a combination of both? (Schema see below)
[Authorize(Roles = "Admin")] //This will pass true to the View if the User is a member of the group "Admin"
public ActionResult Index(){
....
}
#{
if(User.IsAuthenticated){ //This will read the "Token" and if it's true the if statement will get executed.
Some link to be hidden
}
}
So - if the User is in Role "Admin" the link will be shown. Is this possible?
You could use ViewBag and ViewData among other things, but I'd suggest passing a model back to the view with properties indicating whether to display the links or not.
public class YourViewModel()
{
public bool ShowHiddenLinks { get; set; }
// ... whatever other properties
}
In your controller you'd then do:
[Authorize(Roles = "Admin")]
public ActionResult Index()
{
var yourVm = new YourViewModel();
yourVm.ShowHiddenLinks = true;
return View(yourVm);
}
And your view becomes:
#model YourViewModel
/* ShowHiddenLinks is true & this view is meant for admins only,
so show admin-related links */
#if (Model.ShowHiddenLinks)
{
Some link to be hidden
}
I've named the viewmodel property ShowHiddenLinks on purpose, so that it becomes re-usable for views meant for other users as well. You can of course extend the viewmodel to feature properties for other roles (e.g. a view which is accessible by admins and moderators, each with their own distinct set of hidden links), or create one viewmodel per roleā€”it all depends on the scenario.

How to display view model validation for a view that has multiple forms on it?

I'm trying to better understand how to properly structure my ASP.NET MVC code to handle a situation where a single view contains multiple forms. I feel that it makes sense to submit the forms to their own action methods, so that each form can benefit from its own view model parameter binding and validation, and to avoid putting all form parameters into 1 larger, monolithic view model.
I'm trying to code this pattern, but I can't seem to tie the loose ends together.
I've written some example action methods below, along with example view model classes, that I think demonstrate what I'm trying to achieve. Lets say that I've got an Item Detail action method and view. On this Detail view, I've got two forms - one that creates a new Comment and another that creates a new Note. Both Comment and Note forms POST to their own action methods - DetailNewComment and DetailNewNote.
On success, these POST handler action methods work just fine. On an invalid model state though, I return View(model) so that I can display the issues on the original Detail view. This tries to render a view named Brief though, instead of Detail. If I use the overloaded View call that allows me to specify which view to render, then now I have issues with the different view model classes that I'm using. The specific view model classes now no longer work with the original DetailViewModel.
I get the feeling that I'm doing this completely wrong. How am I supposed to be handling this scenario with multiple forms? Thanks!
public ActionResult Detail(int id)
{
var model = new ItemDetailViewModel
{
Item = ItemRepository.Get(id)
};
return View(model);
}
[HttpPost]
public ActionResult DetailNewComment(int id, ItemDetailNewCommentViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
var comment = CommentRepository.Insert(new Comment
{
Text = model.Text
});
return RedirecToAction("Detail", new { id = id; });
}
[HttpPost]
public ActionResult DetailNewNote(int id, ItemDetailNewNoteViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
var note = NoteRepository.Insert(new Note
{
Text = model.Text
});
return RedirectToAction("Detail", new { id = id; });
}
... with view models something like ...
public class ItemDetailViewModel
{
public Item Item { get; set; }
}
public class ItemDetailNewCommentViewModel
{
public string Text { get; set; }
}
public class ItemDetailNewNoteViewModel
{
public string Text { get; set; }
}
For your case I'd recommend to have a master model for example your
ItemDetailViewModel class to which you'll add a property for each sub-model
public class ItemDetailViewModel
{
public Item Item { get; set; }
public ItemDetailNewCommentViewModel NewCommentModel {get;set;}
public ItemDetailNewNoteViewModel NoteModel {get;set;}
}
Your Detail view will be the master view and the other two will be partial views.
Master view will receive an instance of ItemDetailViewModel as model and inside view you will render your partials by passing Model.NewCommentModel and Model.NoteModel as their corresponding models. For being able to use separate actions for each form, instead of regular forms you can use ajax forms, thus you will send to the server only relevant information without altering the rest of the master view.
The chief problem here is what happens when the user messes up and their post doesn't pass validation server-side. If you choose to take them to a page where just the one form is presented, then you can post to a different action, but if you want both forms re-displayed, then they both should point to the same action.
Really, you just have to make a choice. I've seen sites handle it both ways. Personally, I prefer to re-display the original form, which means handling both forms in the same action. It can lead to bloat, but you can factor out a lot of logic from the action such that you end up with mostly just a branch depending on which form was submitted.

MVC3 Html editor helpers display old model value

After form submit Html editor helpers (TextBox, Editor, TextArea) display old value not a current value of model.text
Display helpers (Display, DisplayText) display proper value.
Is there any way editor helpers to display current model.text value?
Model
namespace TestProject.Models
{
public class FormField
{
public string text { get;set; }
}
}
Controller
using System.Web.Mvc;
namespace TestProject.Controllers
{
public class FormFieldController : Controller
{
public ActionResult Index (Models.FormField model=null)
{
model.text += "_changed";
return View(model);
}
}
}
View
#model TestProject.Models.FormField
#using (Html.BeginForm()){
<div>
#Html.DisplayFor(m => m.text)
</div>
<div>
#Html.TextBoxFor(m => m.text)
</div>
<input type="submit" />
}
When you submit the form to an MVC action the values of the input fields are recovered from the POSTEd values available in the form and not from the model. That makes sense right? We don't want the user to show a different value in a textbox than they have just entered and submitted to the server.
If you want to show the updated model to the user then you should have another action and from the post action you have to redirect to that action.
Basically you should have two actions one action that renders the view to edit the model and another one saves the model to database or whatever and redirect the request to the former action.
An example:
public class FormFieldController : Controller
{
// action returns a view to edit the model
public ActionResult Edit(int id)
{
var model = .. get from db based on id
return View(model);
}
// action saves the updated model and redirects to the above action
// again for editing the model
[HttpPost]
public ActionResult Edit(SomeModel model)
{
// save to db
return RedirectToAction("Edit");
}
}
When using HTML editors such as HTML.EditorFor() or HTML.DisplayFor(), if you attempt to modify or change the model values in the controller action you won't see any change unless you remove the ModelState for the model property you want to change.
While #Mark is correct, you don't have to have a separate controller action (but you usually would want to) and you don't need to redirect to the original action.
e.g. - call ModelState.Remove(modelPropertyName)...
public ActionResult Index (Models.FormField model=null)
{
ModelState.Remove("text");
model.text += "_changed";
return View(model);
}
And if you want to have separate actions for GET and POST (recommended) you can do...
public ActionResult Index ()
{
Models.FormField model = new Models.FormField(); // or get from database etc.
// set up your model defaults, etc. here if needed
return View(model);
}
[HttpPost] // Attribute means this action method will be used when the form is posted
public ActionResult Index (Models.FormField model)
{
// Validate your model etc. here if needed ...
ModelState.Remove("text"); // Remove the ModelState so that Html Editors etc. will update
model.text += "_changed"; // Make any changes we want
return View(model);
}
I had some similar problem, I hope I can help others have similar problem:
ActionExecutingContext has Controller.ViewData.
as you can see:
new ActionExecutingContext().Controller.ViewData
This ViewData contains ModelState and Model. The ModelState shows the state of model has passed to controller for example. When you have an error on ModelState the unacceptable Model and its state passed to View. So you will see the old value, yet. Then you have to change the Model value of ModelState manually.
for example for clearing a data:
ModelState.SetModelValue("MyDateTime", new ValueProviderResult("", "", CultureInfo.CurrentCulture));
Also you can manipulate the ViewData, as here.
The EditorFor, DisplayFor() and etc, use this ViewData contents.

How to get the updated contents in a YUI simple editor from your view model

I am using ASP.NET MVC3 with the razor view engine. I am also using a the Yahoo User Interface 2 (YUI2) simple editor.
My view has a view model called ProductEditViewModel. In this view model I have a property defined as:
public string LongDescription { get; set; }
In my view I would create the YUI2 simple editor from this input field. The field is defined in the view like:
<td>#Html.TextAreaFor(x => x.LongDescription, new { cols = "75", rows = "10" })<br>
#Html.ValidationMessageFor(x => x.LongDescription)
</td>
Here is a partial view of my Edit action method:
[Authorize]
[HttpPost]
[ValidateInput(false)]
public ActionResult Edit(ProductEditViewModel viewModel)
{
if (!ModelState.IsValid)
{
// Check if valid
}
// I added this as a test to see what is returned
string longDescription = viewModel.LongDescription;
// Mapping
Product product = new Product();
product.InjectFrom(viewModel);
// Update product in database
productService.Update(product);
return RedirectToRoute(Url.AdministrationProductIndex());
}
When I view the contents of the longDescription variable then it should contain the values from the editor. If I edit the contents in the editor then longDescription still only contains the original contents, not the updated contents. Why is this?
I suspect that somewhere in your POST action you have written something like this:
[Authorize]
[HttpPost]
[ValidateInput(false)]
public ActionResult Edit(ProductEditViewModel viewModel)
{
...
viewModel.LongDescription = "some new contents";
return View(viewModel);
}
If this is the case then you should make sure that you have cleared the value from the ModelState before modifying it because HTML helpers will always first use the value from model state and then from the model.
So everytime you intend to manually modify some property of your view model inside a POST action make sure you remove it from modelstate:
ModelState.Remove("LongDescription");
viewModel.LongDescription = "some new contents";
return View(viewModel);
Now when the view is displayed, HTML helpers that depend on the LongDescription property will pick the new value instead of using the one that was initially submitted by the user.

Resources