Sitecore MVC redirect to another page - sitecore-mvc

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.

Related

How To Switch _Layout view in MVC5

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

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.

Orchard custom module showing blank "Create" page

I created a custom module for Orchard following this wonderful guide.
I have created a controller called BarberAdminController as follows:
[Admin]
public class BarberAdminController : Controller
{
...
public BarberAdminController(IOrchardServices services, IRepository<BarberPart> repository)
{
_repository = repository;
_services = services;
}
...
public ActionResult Create()
{
var barber = _services.ContentManager.New(typeof(BarberPart).ToString());
dynamic model = _services.ContentManager.BuildEditor(barber);
return View(model);
}
}
View:
#{ Layout.Title = T("New Barber").ToString(); }
#using (Html.BeginFormAntiForgeryPost()) {
#Html.ValidationSummary()
// Model is a Shape, calling Display() so that it is rendered using the most specific template for its Shape type
#Display(Model)
}
Upon clicking the link from the admin menu to create a Barber, I get a blank page with nothing but a "Save" button. (URL: /Admin/BarberShop/Barbers/Create)
Does anyone know what I might be doing wrong?
I've set up the routes and admin links and they seem to work fine. I followed the guide as closely as I could on creating the Drivers and Handlers for BarberPart correctly. Including down to the Migration.cs file database schema.
Any help would be great!
I figured it out.
I needed to define a Content Part and Content Type for BarberPart. In Migrations.cs, do:
ContentDefinitionManager.AlterPartDefinition(typeof(BarberPart).Name, p => p
.Attachable(false));
ContentDefinitionManager.AlterTypeDefinition("Barber", t => t
.WithPart(typeof(BarberPart).Name));
In the "Create" method of the Controller, replace:
var barber = _services.ContentManager.New(typeof(BarberPart).ToString());
with:
BarberPart barber = _services.ContentManager.New<BarberPart>("Barber");
Make sure that you have a Drivers/BarberDriver.cs file as such:
public class BarberDriver : ContentPartDriver<BarberPart>
{
protected override DriverResult Editor(BarberPart part, dynamic shapeHelper)
{
return ContentShape("Parts_Barber_Edit", () => shapeHelper.EditorTemplate(TemplateName: "Parts/Barber", Model: part, Prefix: Prefix));
}
protected override DriverResult Editor(BarberPart part, IUpdateModel updater, dynamic shapeHelper)
{
updater.TryUpdateModel(part, Prefix, null, null);
return Editor(part, shapeHelper);
}
}
Be sure to have a part edit template located in /Views/EditorTemplates/Parts/Barber.cshtml that looks like this:
#model SDKU.Barbr.Models.BarberPart
<fieldset>
#Html.EditorFor(model => model.SomePropertyName)
etc...
</fieldset>

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.

Asp.net MVC 3 global querystring?

I'm building a generic web application for two business groups. The logo/banner needs to be changed based on the querystring. For example, if the url is http://foo.com/test?bg=a it shows the logo for business group a and if the url is http://foo.com/test?bg=b it shows the logo for business group b. This is not a problem if I only had one action. But I have many actions.
I could check the query string on all actions but there must be a nice way to do it. I have an perception that I need to do something with the routing stuff but just don't know how. Can anyone please let me know how to do it?
You can write a Custom Routing Handler and use routing to extract the querystring as a parameter, and pass into RouteData where it can be accessed anywhere.
public class RouteWithQueryStringValueHandler : MvcRouteHandler
{
private readonly string key;
public RouteWithQueryStringValueHandler(string key)
: base()
{
this.key = key;
}
protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
{
var request = requestContext.HttpContext.Request;
var qsValue = requestContext.HttpContext.Request[key];
var router = base.GetHttpHandler(requestContext);
requestContext.RouteData.DataTokens[key] = qsValue;
return router;
}
}
Register as follows:
routes.Add(new Route("{controller}/{action}/{id}",
new RouteValueDictionary(
new { controller = "Home",
action = "Index",
id = UrlParameter.Optional
}),
new RouteWithQueryStringValueHandler("bg")));
Get the logo for Routing data:
var logo = RouteData.DataTokens["bg"];
You could write a custom helper method which based on the query string parameter will append a given class name to some div. Then of course you would have different class definitions in your CSS file applying a background-image.
For example:
public static class HtmlExtensions
{
public static string BannerClass(this HtmlHelper html)
{
var bg = html.ViewContext.Controller.ValueProvider.GetValue("bg");
if (bg == null || string.IsNullOrEmpty(bg.AttemptedValue))
{
// no bg parameter => return a default class
return "default_banner";
}
if (string.Equals("a", bg.AttemptedValue))
{
return "banner_a";
}
else if (string.Equals("b", bg.AttemptedValue))
{
return "banner_b";
}
// unknown value for the bg parameter => return a default class
return "default_banner";
}
}
and then in your _Layout you could apply this class to some placeholder like a div or even the body:
<div class="#Html.BannerClass()">OK</div>
This way it will always be applied for all view in your application.
Now all that's left is to define your CSS rules for the different banners:
.default_banner {
background-image: url('../images/default_banner.png')
}
.banner_a {
background-image: url('../images/banner_a.png')
}
.banner_b {
background-image: url('../images/banner_b.png')
}
If you are using Razor (and I believe this does break the separation of responsibilities guideline) change the _ViewStart.cshtml to do it.
#{
if (/* Context.QueryString Params, not at my development box*/)
{
Layout = "~/Views/Shared/Layout-Group1.cshtml";
}
else
{
Layout = "~/Views/Shared/Layout-Group2.cshtml";
}
}
I prefer this route because it makes any future requests (layout + css + javascript) fairly easy because they can all be updated within the Layout.
Place some code in your master page(s) to make the decision as to which banner to display based on the query string. Ideally the code wouldn't be completely inline i.e. it'd be in a helper class.

Resources