AjaxRadioList

Cascading Radio button list using binding to Parent

AjaxRadioList needs an url, js func or controller to get data from, it will render a list of radiobuttons
As with most awesome controls, you can bind the AjaxRadioList to one or more parents, and when the parent changes value the child will load and get the parent values as parameters in its data function
AjaxRadioListDemo/Index.cshtml
@(Html.Awe().AjaxRadioListFor(o => o.ParentCategory)
.Url(Url.Action("GetCategories", "Data")))
@(Html.Awe().AjaxRadioListFor(o => o.ChildMeal)
.Url(Url.Action("GetMeals", "Data"))
.Parent(o => o.ParentCategory, "categories"))
Awesome/DataController.cs
public IActionResult GetCategories()
{
return Json(Db.Categories.Select(o => new KeyContent(o.Id, o.Name)));
}

public IActionResult GetMeals(int[] categories)
{
categories = categories ?? new int[] { };
var items = Db.Meals.Where(o => categories.Contains(o.Category.Id))
.Select(o => new KeyContent(o.Id, o.Name));

return Json(items);
}

Client data

Besides remote data using .Url(str), it can also get data from the client using .DataFunc(jsFunc), the jsFunc can return the items or a Promise
AjaxRadioListDemo/Index.cshtml
<script>
function getClientData() {
return [{ k: 1, c: 'Fruits' }, { k: 2, c: 'Vegetables' }, { k: 3, c: 'Nuts' }];
}
</script>
@(Html.Awe().AjaxRadioList("CatClient1")
.DataFunc("getClientData")
.Value(2)
.Ochk())

Ochk

AjaxRadioListDemo/Index.cshtml
<div class="ib arl">
@(Html.Awe().AjaxRadioList("ParentCatOchk")
.Value(Db.Categories[2].Id)
.Ochk()
.Url(Url.Action("GetCategories", "Data")))
</div>
<div class="ib arl">
@(Html.Awe().AjaxRadioList("ChildMealOchk")
.DataFunc("getMealsChild")
.Ochk(o => o.ItemFunc("site.imgItem"))
.Value(new[] { 185, 187 })
.Parent("ParentCatOchk", "categories"))
</div>

ButtonGroup

AjaxRadioListDemo/Index.cshtml
@(Html.Awe().AjaxRadioList("CategoriesButtonGroup")
.ButtonGroup()
.Url(Url.Action("GetCategories", "Data")))

Odropdown



DropdownList with search functionality. Search can be local or remote if you set SearchFunc.
Odropdown/Index.cshtml
@(Html.Awe().AjaxRadioList("AllMealsOdropdown")
.Odropdown()
.Url(Url.Action("GetAllMeals", "Data")))
Awesome/DataController.cs
public IActionResult GetAllMeals()
{
var items = Db.Meals.Select(o => new KeyContent(o.Id, o.Name));
return Json(items);
}

Cascading Odropdowns

Odropdown/Index.cshtml
@(Html.Awe().AjaxRadioList("CatOdropdown")
.Odropdown()
.Url(Url.Action("GetCategories", "Data")))

@(Html.Awe().AjaxRadioList("MealsOdropdown")
.Odropdown(o => o.AutoSelectFirst())
.Url(Url.Action("GetMeals", "Data"))
.Parent("CatOdropdown", "categories"))
Awesome/DataController.cs
public IActionResult GetMeals(int[] categories)
{
categories = categories ?? new int[] { };
var items = Db.Meals.Where(o => categories.Contains(o.Category.Id))
.Select(o => new KeyContent(o.Id, o.Name));

return Json(items);
}

Odropdown with grouped items



Odropdown/Index.cshtml
@(Html.Awe().AjaxRadioList("MealsGrouped")
.Odropdown()
.Url(Url.Action("GetAllMealsGrouped", "Data")))
Awesome/DataController.cs
public IActionResult GetAllMealsGrouped()
{
var res = new List<Oitem>();
var groups = Db.Meals.GroupBy(o => o.Category);
foreach (var g in groups)
{
res.Add(new Oitem
{
Content = g.Key.Name,
Class = "o-itm o-itmg",
NonVal = true,
Items = g.Select(meal => new Oitem(meal.Id, meal.Name)),
});
}

return Json(res);
}

Odropdown with submenu



Odropdown/Index.cshtml
@(Html.Awe().AjaxRadioList("MealsSbm")
.Odropdown(o => o.Submenu()
.ItemFunc("site.imgItem")
.CaptionFunc("utils.imgCaption"))
.Url(Url.Action("GetMealsTreeImg", "Data")))
Awesome/DataController.cs
public IActionResult GetMealsTreeImg()
{
var url = Url.Content(DemoUtils.MealsUrl);

var res = new List<MealOitem>();
var groups = Db.Meals.GroupBy(o => o.Category);
foreach (var g in groups)
{
res.Add(new MealOitem
{
Content = g.Key.Name,
Class = "o-itm",
NonVal = true,
Items = g.Select(meal => new MealOitem { Key = meal.Id, Content = meal.Name, url = url + meal.Name + ".jpg" })
});
}

return Json(res);
}

Odropdown with fav buttons





Odropdown/Index.cshtml
@(Html.Awe().AjaxRadioList("AllMealsFav")
.Url(Url.Action("GetMealsImg", "Data"))
.CssClass("bigFavs")
.Odropdown(o => o.Favs()
.ItemFunc("site.imgItem")
.CaptionFunc("utils.imgCaption")))

<br />
<br />
@(Html.Awe().AjaxRadioList("AllMealsFav2")
.Url(Url.Action("GetMealsImg", "Data"))
.CssClass("bigFavs")
.Odropdown(o => o.Favs(3, favs:new object[]{Db.Meals[3].Id, Db.Meals[15].Id }, frozen: new object[]{ Db.Meals[5].Id })
.ItemFunc("site.imgItem")
.CaptionFunc("utils.imgCaption")))

Odropdown, tree data, lazy nodes, remote search



Odropdown/Index.cshtml
@(Html.Awe().AjaxRadioList("RmtLazyTree")
.Url(Url.Action("GetTreeNodesLazy", "Data"))
.Odropdown(o => o.CollapseNodes()
.ClearBtn()
.PopupMinWidth(350)
.SearchFunc("utils.osearch", Url.Action("SearchTree", "Data"))))
Awesome/DataController.cs
public IActionResult GetTreeNodesLazy(int? key)
{
// key has value, lazy request
var nodes = key.HasValue ?
buildItemTrees(Db.TreeNodes.Where(o => o.Id == key)).Take(10) :

// initial load, return roots (parent is null)
buildItemTrees(Db.TreeNodes.Where(o => o.Parent == null).Take(10), setLazyChild: true);

return Json(nodes);
}

/// <summary>
/// builds oitem tree collection from treeNodes collection
/// </summary>
private IEnumerable<Oitem> buildItemTrees(IEnumerable<TreeNode> nodes, int lvl = 0, bool setLazyChild = false)
{
var list = new List<Oitem>();
foreach (var node in nodes)
{
var oitem = new Oitem { Key = node.Id.ToString(), Content = node.Name };
list.Add(oitem);
var children = Db.TreeNodes.Where(o => o.Parent == node);

if (!children.Any()) continue;

// set node as lazy after lvl 0
if (setLazyChild && lvl > 0)
{
oitem.Lazy = true;
}
else
{
oitem.Items = buildItemTrees(children, lvl + 1, setLazyChild);
}
}

return list;
}

public IActionResult SearchTree(string term)
{
term = (term ?? string.Empty).ToLower();
var result = Db.TreeNodes.Where(o => o.Name.ToLower().Contains(term)).Take(1).ToList();
var roots = new List<TreeNode>();

foreach (var treeNode in result)
{
roots.Add(getRoot(treeNode));
}

roots = roots.Distinct().ToList();

var nodes = buildItemTrees(roots);
return Json(nodes);
}

private TreeNode getRoot(TreeNode node)
{
return node.Parent == null ? node : getRoot(node.Parent);
}

Odropdown with remote search

try 'o'

Only a few items + the selected one are loaded initially using the url specified in .Url, but when the user types something in the searchbox more items are loaded by executing the specified .SearchFunc; the new loaded items will be stored/cached until a load will occur, e.g. when a parent changes it's value the component will load.
Components with the same cache key ("m1", "g") have a shared cache.
Odropdown/Index.cshtml
@(Html.Awe().AjaxRadioList("RemoteSearchOdropdown")
.Odropdown(o => o.SearchFunc("utils.osearch", Url.Action("SearchMeals", "Data"), "m1").ClearBtn())
.Value(197)
.Url(Url.Action("GetMealsInit", "Data")))

@(Html.Awe().AjaxRadioList("RemoteSearchCombobox")
.Combobox(o => o.SearchFunc("utils.osearch", Url.Action("SearchMeals", "Data"), "m1"))
.Value(197)
.Url(Url.Action("GetMealsInit", "Data"))) <span class="hint">try 'o'</span>
Awesome/DataController.cs
public IActionResult GetMealsInit(int? v)
{
var items = Db.Meals.Take(3).ToList();
var selected = Db.Meals.SingleOrDefault(o => o.Id == v);

if (selected != null && !items.Contains(selected))
{
items.Add(selected);
}

return Json(items.Select(o => new KeyContent(o.Id, o.Name)));
}

public IActionResult SearchMeals(string term = "")
{
var items = Db.Meals
.Where(o => o.Name.IndexOf(term, StringComparison.OrdinalIgnoreCase) >= 0)
.Take(10)
.Select(o => new KeyContent(o.Id, o.Name));

return Json(items);
}

Remote search, external api

try 'valueinjecter'



Getting data from the git api on search using the SearchFunc. ItemFunc and CaptionFunc are used to specify custom rendering functions for the items and the caption.
Using the same cache key "g1", so searching in one control will populate the other one with data as well.
Shared/Demos/RmtSrcGit.cshtml
@(Html.Awe().AjaxRadioList("GitRepoOdropdown")
.Load(false)
.Odropdown(o =>
o.SearchFunc("site.gitRepoSearch", key: "g1")
.ItemFunc("site.gitItem")
.CaptionFunc("site.gitCaption")
.Caption("select a git repo")))
<span class="hint">try 'valueinjecter'</span>
<br/>
<br/>
@(Html.Awe().AjaxCheckboxList("GitRepoMultiselect")
.Load(false)
.Multiselect(o =>
o.SearchFunc("site.gitRepoSearch", key: "g1")
.ItemFunc("site.gitItem")
.CaptionFunc("site.gitCaption")
.Caption("select a git repo")))

Odropdown with custom item and caption rendering



Custom js functions are defined for rendering the items and caption of the odropdown.
AjaxRadioListDemo/Index.cshtml
@(Html.Awe().AjaxRadioList("CustomItemOdd")
.Value(Db.Meals[1].Id)
.Url(Url.Action("GetMealsImg", "Data"))
.Odropdown(o => o.ItemFunc("imgItem").CaptionFunc("imgCaption")))
<script>
function imgItem(o) {
return '<div class="o-igit"><img src="' + o.url + '" />' + o.c + '</div>';
}

function imgCaption(o) {
return '<img class="cthumb" src="' + o.url + '" />' + o.c;
}
</script>
Awesome/DataController.cs
public IActionResult GetMealsImg()
{
var url = Url.Content(DemoUtils.MealsUrl);
var items = Db.Meals
.Select(o => new MealDisplay(o.Id, o.Name, url + o.Name + ".jpg", o.Category.Id));

return Json(items);
}

Combobox

AjaxRadioListDemo/Index.cshtml
@(Html.Awe().AjaxRadioList("AllMealsCombo")
.Value("combo value")
.Combobox()
.Url(Url.Action("GetMealsImg", "Data")))

Color dropdown

AjaxRadioListDemo/Index.cshtml
@(Html.Awe().AjaxRadioList("ColorPicker1")
.ColorDropdown(o => o.AutoSelectFirst()))

TimePicker

AjaxRadioListDemo/Index.cshtml
@(Html.Awe().AjaxRadioList("TimePicker1")
.TimePicker(o => o.Caption("time please").Step(15).ClearBtn()))

Set value from get items call

Note how in the second editor the second item is selected on load.
Odropdown/Index.cshtml
@using AweCoreDemo.Models
@{
ViewBag.Title = "Odropdown - Dropdownlist control with search functionality";
}

<h1>Odropdown</h1>
<div class="expl">
DropdownList with search functionality. Search can be local or remote if you set <code>SearchFunc</code>. <br />
Other features: items grouping, tree structure, lazy nodes, fav buttons, show tree structure as submenus, custom item and caption rendering.<br />
It will receive data from <code>Url</code> or from <code>DataFunc</code> which must return either an array of items or a promise (e.g. ajax request).
</div>
<div class="example">
<h2 data-name="odropdown">Odropdown</h2>
@*beginodd*@
@(Html.Awe().AjaxRadioList("AllMealsOdropdown")
.Odropdown()
.Url(Url.Action("GetAllMeals", "Data")))
@*endodd*@
<br />
<br />
<div class="tabs">
<div data-caption="view">@Html.Source("Odropdown/Index.cshtml", "odd")</div>
<div data-caption="controller">@Html.Code("Awesome/DataController.cs").Action("GetAllMeals")</div>
</div>
</div>

<div class="example">
<h2>Cascading Odropdowns</h2>
@*begincc*@
@(Html.Awe().AjaxRadioList("CatOdropdown")
.Odropdown()
.Url(Url.Action("GetCategories", "Data")))

@(Html.Awe().AjaxRadioList("MealsOdropdown")
.Odropdown(o => o.AutoSelectFirst())
.Url(Url.Action("GetMeals", "Data"))
.Parent("CatOdropdown", "categories"))
@*endcc*@

<div class="tabs code">
<div data-caption="view">@Html.Source("Odropdown/Index.cshtml", "cc")</div>
<div data-caption="controller">@Html.Code("Awesome/DataController.cs").Action("GetMeals")</div>
</div>
</div>

<div class="example">
<h2>Odropdown with grouped items</h2>
@*beginamg*@
@(Html.Awe().AjaxRadioList("MealsGrouped")
.Odropdown()
.Url(Url.Action("GetAllMealsGrouped", "Data")))
@*endamg*@
<br />
<br />
<div class="tabs code">
<div data-caption="view">@Html.Source("Odropdown/Index.cshtml", "amg")</div>
<div data-caption="controller">@Html.Csource("Awesome/DataController.cs", "amg")</div>
</div>
</div>

<div class="example">
<h2>Odropdown with submenu</h2>
@*beginsbm*@
@(Html.Awe().AjaxRadioList("MealsSbm")
.Odropdown(o => o.Submenu()
.ItemFunc("site.imgItem")
.CaptionFunc("utils.imgCaption"))
.Url(Url.Action("GetMealsTreeImg", "Data")))
@*endsbm*@
<br />
<br />
<div class="tabs code">
<div data-caption="view">@Html.Source("Odropdown/Index.cshtml", "sbm")</div>
<div data-caption="controller">@Html.Csource("Awesome/DataController.cs", "sbm")</div>
</div>
</div>

<div class="example">
<h2 data-name="odropdownfav">Odropdown with fav buttons</h2>
@*beginfav*@
@(Html.Awe().AjaxRadioList("AllMealsFav")
.Url(Url.Action("GetMealsImg", "Data"))
.CssClass("bigFavs")
.Odropdown(o => o.Favs()
.ItemFunc("site.imgItem")
.CaptionFunc("utils.imgCaption")))

<br />
<br />
@(Html.Awe().AjaxRadioList("AllMealsFav2")
.Url(Url.Action("GetMealsImg", "Data"))
.CssClass("bigFavs")
.Odropdown(o => o.Favs(3, favs:new object[]{Db.Meals[3].Id, Db.Meals[15].Id }, frozen: new object[]{ Db.Meals[5].Id })
.ItemFunc("site.imgItem")
.CaptionFunc("utils.imgCaption")))
@*endfav*@
<br />
<br />
<div class="code">
<div data-caption="view">@Html.Source("Odropdown/Index.cshtml", "fav")</div>
</div>
</div>

<div class="example">
<h2>Odropdown, tree data, lazy nodes, remote search</h2>
@*beginlztree*@
@(Html.Awe().AjaxRadioList("RmtLazyTree")
.Url(Url.Action("GetTreeNodesLazy", "Data"))
.Odropdown(o => o.CollapseNodes()
.ClearBtn()
.PopupMinWidth(350)
.SearchFunc("utils.osearch", Url.Action("SearchTree", "Data"))))
@*endlztree*@
<br />
<br />
<div class="tabs code">
<div data-caption="view">@Html.Source("Odropdown/Index.cshtml", "lztree")</div>
<div data-caption="controller">@Html.Csource("Awesome/DataController.cs", "tree")</div>
</div>
</div>

<div class="example">
<h2 data-name="oremotesearch">Odropdown with remote search</h2>
@*beginrs*@
@(Html.Awe().AjaxRadioList("RemoteSearchOdropdown")
.Odropdown(o => o.SearchFunc("utils.osearch", Url.Action("SearchMeals", "Data"), "m1").ClearBtn())
.Value(197)
.Url(Url.Action("GetMealsInit", "Data")))

@(Html.Awe().AjaxRadioList("RemoteSearchCombobox")
.Combobox(o => o.SearchFunc("utils.osearch", Url.Action("SearchMeals", "Data"), "m1"))
.Value(197)
.Url(Url.Action("GetMealsInit", "Data"))) <span class="hint">try 'o'</span>
@*endrs*@
<br />
<br />
<div class="tabs">
<div data-caption="description" class="expl">
Only a few items + the selected one are loaded initially using the url specified in .Url, but when the user types something in the searchbox more items
are loaded by executing the specified .SearchFunc; the new loaded items will be stored/cached until a load will occur, e.g. when a parent changes it's value the component will load.
<br />
Components with the same cache key ("m1", "g") have a shared cache.
</div>
<div data-caption="view">@Html.Source("Odropdown/Index.cshtml", "rs")</div>
<div data-caption="controller">@Html.Csource("Awesome/DataController.cs", "rso")</div>
</div>
</div>

<div class="example">
@await Html.PartialAsync("Demos/RmtSrcGit")
</div>



<div class="example">
<h2 data-name="odropdown">Odropdown with custom item and caption rendering</h2>
@*beginoddci*@
@(Html.Awe().AjaxRadioList("CustomItemOdd")
.Value(Db.Meals[1].Id)
.Url(Url.Action("GetMealsImg", "Data"))
.Odropdown(o => o.ItemFunc("imgItem").CaptionFunc("imgCaption")))
<script>
function imgItem(o) {
return '<div class="o-igit"><img src="' + o.url + '" />' + o.c + '</div>';
}

function imgCaption(o) {
return '<img class="cthumb" src="' + o.url + '" />' + o.c;
}
</script>
@*endoddci*@
<br />
<br />
<div class="tabs">
<div data-caption="description" class="expl">
Custom js functions are defined for rendering the items and caption of the odropdown.
</div>
<div data-caption="view">@Html.Source("AjaxRadioListDemo/Index.cshtml", "oddci")</div>
<div data-caption="controller">@Html.Csource("Awesome/DataController.cs", "img")</div>
</div>
</div>
Awesome/DataController.cs
public IActionResult GetMealsSetValue2(int[] categories)
{
categories = categories ?? new int[] { };

var items = Db.Meals.Where(o => categories.Contains(o.Category.Id)).ToList();

object value = null;
if (items.Any())
{
value = items.Skip(1).First().Id;
}

return Json(new AweItems
{
Items = items.Select(o => new KeyContent(o.Id, o.Name)),
Value = value
});
}

Using predefined parameters

setting parameter parent = { Fruits, Legumes } using .Parameter and .ParameterFunc extensions

Events and Api






Showing commonly used client side api methods.
To change the value you simply call jquery .val(newvalue).change().
aweload event is handled to flash the #log div whenever the dropdown loads.
The same api methods can be used for the AjaxDropdown, AjaxCheckboxList controls and their mods.
AjaxRadioListDemo/Index.cshtml
@{
var meal1 = Db.Meals[3];
var meal2 = Db.Meals[4];
}

@(Html.Awe().AjaxRadioList("ddApi")
.Odropdown()
.Url(Url.Action("ApiGetMeals", "Data")))

<br />
<br />
@Html.Awe().Button().Text("Change value to " + meal1.Name).OnClick("app1.changeval(" + meal1.Id + ")")
@Html.Awe().Button().Text("Change value to " + meal2.Name).OnClick("app1.changeval(" + meal2.Id + ")")
@Html.Awe().Button().Text("Get value").OnClick("app1.getVal()")
@Html.Awe().Button().Text("Clear Value").OnClick("app1.changeval('')")

@Html.Awe().Button().Text("Load only first category").OnClick("app1.loadFirstCat()")
@Html.Awe().Button().Text("Reload").OnClick("app1.reload()")
@Html.Awe().Button().Text("Toggle Enable").OnClick("app1.toggleEnable()")

<br />
<br />

<div id="log">
</div>

<script>
var app1;

$(function () {
var dd = $('#ddApi');
var api = dd.data('api');
app1 = {
getVal: function () {
var val = dd.val();
$('#log').html('val = ' + val);
},

changeval: function (newVal) {
dd.val(newVal).change();
},

reload: function () {
api.load();
},

loadFirstCat: function () {
api.load({ oparams: { cat1: true } });
// oparams sets cat1 just for this call (same as for the grid api)
// params sets persistent parameters
},

toggleEnable: function () {
api.enable(!dd.data('o').enb);
}
};

dd.on('aweload', function (e, data) {
awe.flash($('#log').html('loaded ' + data.length + ' items'));
});
});
</script>
Awesome/DataController.cs
public IActionResult ApiGetMeals(int? v, bool? cat1)
{
var items = Db.Meals;

if (cat1.HasValue && cat1.Value)
{
items = items.Where(o => o.Category == Db.Categories[0]).ToList();
}

return Json(items.Select(o => new KeyContent(o.Id, o.Name)));
}



Comments