Orchard CMS rendering parts outside of admin section - asp.net-mvc-3

I am working on a module by following the instructions here http://orchardproject.net/docs/Creating-a-module-with-a-simple-text-editor.ashx
The one change I want to do is, rendering the product creation outside of admin module. So I created homecontroller like this
public class HomeController : Controller
{
public HomeController(IContentManager cm) {
ContentManager = cm;
}
private IContentManager ContentManager { get; set; }
public ActionResult Index() {
return Content("This is index");
} [Themed]
public ActionResult Create()
{
var product = ContentManager.New("Product");
var model = ContentManager.BuildEditor(product);
return View((object) model);
}
and a file routes.cs in the root folder
public class Routes : IRouteProvider
{
public void GetRoutes(ICollection<RouteDescriptor> routes)
{
foreach (var routeDescriptor in GetRoutes())
routes.Add(routeDescriptor);
}
public IEnumerable<RouteDescriptor> GetRoutes()
{
return new[] {
new RouteDescriptor {
Priority = 5,
Route = new Route(
"commerce",
new RouteValueDictionary {
{"area", "SimpleCommerce"},
{"controller", "Home"},
{"action", "Index"}
},
new RouteValueDictionary(),
new RouteValueDictionary {
{"area", "SimpleCommerce"}
},
new MvcRouteHandler())
},
new RouteDescriptor {
Priority = 6,
Route = new Route(
"commerce/Create",
new RouteValueDictionary {
{"area", "SimpleCommerce"},
{"controller", "Home"},
{"action", "Create"}
},
new RouteValueDictionary(),
new RouteValueDictionary {
{"area", "SimpleCommerce"}
},
new MvcRouteHandler())
}
};
}
}
So how should I move from here onwards to render this whole thing together when I navigate to url http://localhost:35713/commerce/create
But it throws an error saying create view didnt find. Then I created a view (create.cshtml) in Views/Home folder
#model SimpleCommerce.Models.ProductPart
<fieldset>
<label class="sub" for="Sku">#T("Sku")</label><br />
#Html.TextBoxFor(m => m.Sku, new { #class = "text" })<br />
<label class="sub" for="Price">#T("Price")</label><br />
#Html.TextBoxFor(m => m.Price, new { #class = "text" })
</fieldset>
Now it throws an error saying
The model item passed into the dictionary is of type 'IShapeProxyedcfa08c61cf49898dc2e77bde025039', but this dictionary requires a model item of type 'SimpleCommerce.Models.ProductPart'.

Oh, that's cross-posted. BuildEditor is creating a shape, and your template is expecting a strongly-typed model. Dropping the #Model directive should substitute that problem with another (which is that you won't be able to use the Lambda-based helpers with shapes.

Related

Kendo UI Create ButtonGroup control using a viewmodel

I'm trying to find an example to create a ButtonGroup using a viewmodel.
How can I do that?
#(Html.Kendo().ButtonGroup().Name("PredictionType").Items(t =>
{
t.Add().Text("Monthly");
t.Add().Text("Weekly");
t.Add().Text("Yearly");
}))
ButtonGroup does not have a DataSource configuration item like Grid or DropDownList. Use a Razor code block in the HtmlHelper to loop over a list of items that are added. This example has the controller creating the list of items.
View - Views\Example1\Index.cshtml
#model Example.ViewModels.MySettings
#{
ViewBag.Title = "Index";
}
<div>
Prediction Type
#(Html.Kendo().ButtonGroup()
.Name("PredictionType")
.Items(t =>
{
foreach (var item in Model.PredictionTypeItems)
{
t.Add().Text(item);
}
})
)
</div>
<div>
Exponent Level
#(Html.Kendo().ButtonGroup()
.Name("ExponentLevel")
.Items(t =>
{
foreach (var item in Model.ExponentLevelItems)
{
t.Add().Text(item.ToString());
}
})
)
</div>
Model - ViewModels\MySetting.cs
using System.Collections.Generic;
namespace Example.ViewModels
{
public class MySettings
{
public IList<string> PredictionTypeItems { get; set; }
public IList<int> ExponentLevelItems { get; set; }
}
}
Controller - Controllers\Example1Controller.cs
using System.Collections.Generic;
using System.Web.Mvc;
using Example.ViewModels;
namespace Example.Controllers
{
public class Example1Controller : Controller
{
public ActionResult Index()
{
var model = new MySettings {
PredictionTypeItems = new List<string> { "Monthly", "Weekly", "Yearly" },
ExponentLevelItems = new List<int> { -2, -1, 0, 1, 2 }
};
return View(model);
}
}
}
A more robust scenario would have the items come out of a data base table.

how to register onclick event to #Html.RadioButtonForSelectList in asp.net mvc 3.0

My Model
public class IndexViewModel
{
public IEnumerable<SelectListItem> TestRadioList { get; set; }
[Required(ErrorMessage = "You must select an option for TestRadio")]
public String TestRadio { get; set; }
[Required(ErrorMessage = "You must select an option for TestRadio2")]
public String TestRadio2 { get; set; }
}
public class aTest
{
public Int32 ID { get; set; }
public String Name { get; set; }
}
My Controller
public ActionResult Index()
{
List<aTest> list = new List<aTest>();
list.Add(new aTest() { ID = 1, Name = "Yes" });
list.Add(new aTest() { ID = 2, Name = "No" });
list.Add(new aTest() { ID = 3, Name = "Not applicable" });
list.Add(new aTest() { ID = 3, Name = "Muttu" });
SelectList sl = new SelectList(list, "ID", "Name");
var model = new IndexViewModel();
model.TestRadioList = sl;
return View(model);
}
My View
#using (Html.BeginForm()) {
<div>
#Html.RadioButtonForSelectList(m => m.TestRadio, Model.TestRadioList)
</div>
}
Helper method
public static class HtmlExtensions
{
public static MvcHtmlString RadioButtonForSelectList<TModel, TProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
IEnumerable<SelectListItem> listOfValues)
{
var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
var sb = new StringBuilder();
if (listOfValues != null)
{
// Create a radio button for each item in the list
foreach (SelectListItem item in listOfValues)
{
// Generate an id to be given to the radio button field
var id = string.Format("{0}_{1}", metaData.PropertyName, item.Value);
// Create and populate a radio button using the existing html helpers
var label = htmlHelper.Label(id, HttpUtility.HtmlEncode(item.Text));
var radio = htmlHelper.RadioButtonFor(expression, item.Value, new { id = id }).ToHtmlString();
// Create the html string that will be returned to the client
// e.g. <input data-val="true" data-val-required="You must select an option" id="TestRadio_1" name="TestRadio" type="radio" value="1" /><label for="TestRadio_1">Line1</label>
sb.AppendFormat("<div class=\"RadioButton\">{0}{1}</div>", radio, label);
}
}
return MvcHtmlString.Create(sb.ToString());
}
}
Here is the code i'm using... not sure how to give a onclick event for the control. In the helper method i could not find any appropriate htmlattributes parameter. as per my requirement. on click of any radiobutton in the list i need to call a js function with few parameters. which i'm not able to do. Someonce please help. Thanks in advance.
I haven't got the means to test this at the moment, but a rough idea is adding IDictionary htmlAttributes to the method and passing it in there. If you dont have the required onClick code in the view, then you could omit the parameter and do it in the extension method
public static class HtmlExtensions
{
public static MvcHtmlString RadioButtonForSelectList<TModel, TProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
IEnumerable<SelectListItem> listOfValues,
IDictionary<string, Object> htmlAttributes)
{
var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
var sb = new StringBuilder();
if (listOfValues != null)
{
// Create a radio button for each item in the list
foreach (SelectListItem item in listOfValues)
{
// Generate an id to be given to the radio button field
var id = string.Format("{0}_{1}", metaData.PropertyName, item.Value);
// Create and populate a radio button using the existing html helpers
var label = htmlHelper.Label(id, HttpUtility.HtmlEncode(item.Text));
htmlAttributes["id"] = id;
var radio = htmlHelper.RadioButtonFor(expression, item.Value, htmlAttributes).ToHtmlString();
// Create the html string that will be returned to the client
// e.g. <input data-val="true" data-val-required="You must select an option" id="TestRadio_1" name="TestRadio" type="radio" value="1" /><label for="TestRadio_1">Line1</label>
sb.AppendFormat("<div class=\"RadioButton\">{0}{1}</div>", radio, label);
}
}
return MvcHtmlString.Create(sb.ToString());
}
}
and then call it using something like:
#Html.RadioButtonForSelectList(m => m.TestRadio, Model.TestRadioList, new { onclick="someFunction();" })
alternatively you could set a css class and bind to the click event. for example,
<script type="text/javascript>
$('.someClassName').click( function() {
alert('clicked');
});
</script>
#Html.RadioButtonForSelectList(m => m.TestRadio, Model.TestRadioList, new { #class="someClassName" })

MVC3 Areas routing conflict

Question: i want my route to be like that
/admin/main/category/1 -> 1 == ?page=1
i don't want page=1 to be seen
My Controller
public class MainController : BaseController
{
private const int PageSize = 5; //pager view size
[Inject]
public ICategoryRepository CategoryRepository { get; set; }
public ActionResult Index()
{
return View();
}
public ActionResult Category(int page)
{
//int pageIndex = page.HasValue ? page.Value : 1;
int pageIndex = page != 0 ? page : 1;
return View("Category", CategoryViewModelFactory(pageIndex));
}
/*
*Helper: private instance/static methods
======================================================================*/
private CategoryViewModel CategoryViewModelFactory(int pageIndex) //generate viewmodel category result on pager request
{
return new CategoryViewModel
{
Categories = CategoryRepository.GetActiveCategoriesListDescending().ToPagedList(pageIndex, PageSize)
};
}
}
public class AdminAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "admin";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRouteLowercase(
"AdminCategoryListView",
"admin/{controller}/{action}/{page}",
new { controller = "Category", action = "Category", page = "1" },
new { id = #"\d+" },
new[] { "WebUI.Areas.Admin.Controllers" }
);
}
}
My Exception:
The parameters dictionary contains a null entry for parameter 'page'
of non-nullable type 'System.Int32' for method
'System.Web.Mvc.ActionResult Category(Int32)' in
'WebUI.Areas.Admin.Controllers.MainController'. An optional parameter
must be a reference type, a nullable type, or be declared as an
optional parameter. Parameter name: parameters
Thank you all in advance.
Make sure that in your Admin area route registration you have defined the {page} route token instead of {id} which is generated by default:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{page}",
new { action = "Index", page = UrlParameter.Optional }
);
}
Now when you are generating links make sure you specify this parameter:
#Html.ActionLink(
"go to page 5", // linkText
"category", // actionName
"main", // controllerName
new { area = "admin", page = "5" }, // routeValues
null // htmlAttributes
)
will emit:
go to page 5
and when this url is requested the Category action will be invoked and passed page=5 parameter.

ASP.NET MVC 3 WebGrid, preserve the paging and define the route

I am start to learn the MVC3, But i have some problem on WebGrid,
The Controller name is TestController, so i navigate to :
http://localhost:53503/Test/
And the Webgrid shown as below:
two column : ID and Name.
the 3rd & 4th column : Actionlink and item.GetSelectLink.
The first problem is :
Assume i viewing page 3 of webgrid, and press the ActionLink,after go-thought the TestContoller's Action, the webgrid will return to page 1 after PostBack.
However,if i press the [View(GetSelectLink)] on right end:
(e.g. http://localhost:53503/Test/?gridItems_page=3&gridItems_selectedRow=3
It works.
So, i should use ActionLink or GetSelectLink for general Add/Update/Delete operation?
MVC3 hasn't viewstate / control state, so how can i preserve the current page selection after PostBack?
The second problem is :
The (href) of ActionLink is :
http://localhost:53503/Test/GetSelection/7?Name=PSP
I would make it to
http://localhost:53503/Test/GetSelection/7/PSP
I add a new route to global.asax, but it is no luck.
Thanks you very much for help.
It is my code:
Views/Test/Index.cshtml
#model List<MvcContract.Controllers.Products>
#{
System.Web.Helpers.WebGrid grid = new System.Web.Helpers.WebGrid(
source: Model,
canPage: true,
rowsPerPage: 3,
fieldNamePrefix: "gridItems_",
pageFieldName: "page",
selectionFieldName: "selectedRow"
);
}
#{
if (Model != null)
{
#grid.GetHtml(
columns: grid.Columns(
grid.Column("ID"),
grid.Column("Name"),
grid.Column(format: (item) => Html.ActionLink("View(ActionLink)", "GetSelection", new { ID = item.ID, Name = item.Name })),
grid.Column(format: (item) => item.GetSelectLink("View(GetSelectLink)"))
)
);
}
}
Controllers/TestController.cs
namespace MvcContract.Controllers
{
public class Products
{
public string ID { get; set; }
public string Name { get; set; }
public List<Products> GetItems()
{
List<Products> items = new List<Products>();
items.Add(new Products() { ID = "1", Name = "PS3" });
items.Add(new Products() { ID = "2", Name = "XBox360" });
items.Add(new Products() { ID = "3", Name = "Wii" });
items.Add(new Products() { ID = "4", Name = "Saturn" });
items.Add(new Products() { ID = "5", Name = "Dreamcast" });
items.Add(new Products() { ID = "6", Name = "NDS" });
items.Add(new Products() { ID = "7", Name = "PSP" });
items.Add(new Products() { ID = "8", Name = "NeoGeo" });
items.Add(new Products() { ID = "9", Name = "3DO" });
items.Add(new Products() { ID = "10", Name = "Playdia" });
return items;
}
}
public class TestController : Controller
{
//Bind data to WebGrid
public ActionResult Index()
{
Products products = new Products();
return View(products.GetItems());
}
//Some Logic
public ActionResult GetSelection(string ID, string Name)
{
string SelectedID = ID;
return RedirectToAction("Index");
}
}
}
RegisterRoutes() in Global.asax.cs
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
routes.MapRoute(
"Test_GetSelection", // Route name
"{controller}/{action}/{id}/{name}", // URL with parameters
new { controller = "Test", action = "GetSelection", id = UrlParameter.Optional, name = UrlParameter.Optional } // Parameter defaults
);
}
Check out this discussion. I think one of several solutions there may solve your issue.
Since its been a whole year since you posted this, please post an answer if you figured it out another way.

MVC3- Radion Button Grouping and Binding from database

How to get the radio button options from database using in MVC3 Razor. I have 4 options for each question, the options should be populated from the database and should be grouped.
#Html.RadioButtonFor(model => Model.AAAa, 'Y', new { title = "Please check this if AAA has been updated" })
Yes
This gives me hard coded value as Yes but text needs to be populated with DB Table.
How would I bind it back the selected value back to the database?. An Example would be more helpful.
Thank you
As always you start by defining a view model that will represent the information you will be dealing with in the view:
public class MyViewModel
{
public string SelectedValue { get; set; }
// In your question you seem to be dealing with a title attribute as well
// If this is the case you could define a custom view model ItemViewModel
// which will contain the Value, the Text and the Title properties for
// each radio button because the built-in SelectListItem class that I am using here
// has only Value and Text properties
public SelectListItem[] Items { get; set; }
}
then you write a controller:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new MyViewModel
{
// Obviously those will come from your database or something
Items = new[]
{
new SelectListItem { Value = "Y", Text = "Yes" },
new SelectListItem { Value = "N", Text = "No" },
new SelectListItem { Value = "D", Text = "Dunno" }
}
};
return View(model);
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
return View(model);
}
}
then a corresponding view:
#model MyViewModel
#using (Html.BeginForm())
{
for (int i = 0; i < Model.Items.Count; i++)
{
#Html.RadioButtonFor(x => x.SelectedValue, Model.Items[i].Value, new { id = "item_" + i })
#Html.Label("item_" + i, Model.Items[i].Text)
<br/>
}
<button type="submit">OK</button>
}
or to make the view less messy you could write a custom HTML helper that will render those radio buttons for you:
public static class HtmlExtensions
{
public static IHtmlString RadioButtonListFor<TModel, TProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
IEnumerable<SelectListItem> items
)
{
var sb = new StringBuilder();
var i = 0;
foreach (var item in items)
{
var id = string.Format("item{0}", i++);
var radio = htmlHelper.RadioButtonFor(expression, item.Value, new { id = id });
var label = htmlHelper.Label(id, item.Text);
sb.AppendFormat("{0}{1}<br/>", radio, label);
}
return new HtmlString(sb.ToString());
}
}
and now your view will simply become:
#model MyViewModel
#using (Html.BeginForm())
{
#Html.RadioButtonListFor(x => x.SelectedValue, Model.Items)
<button type="submit">OK</button>
}
which obviously is nicer to look.

Resources