How to update MudSelect Items on BlazorSever - blazor-server-side

Lets say I have two MudSelect controls:
<MudSelect Class="pa-4" T="string" Label="Market" #bind-Value="Market" TextChanged="MarketChanged">
#foreach (var market in markets)
{
<MudSelectItem T="string" Value="#market">#market</MudSelectItem>
}
</MudSelect>
<MudSelect #ref="applicationSelector" Class="pa-4" T="string" Label="Application" #bind-Value="Application"/>
Now when selecting another market, I want the selectable items in Application Selector to be updated dependent on the selection:
private Dictionary<string, List<string>> marketApplications { get; set; } = new Dictionary<string, List<string>>() {
{ "Market 1", new List<string>() { "Application 1" } },
{ "Market 2", new List<string>() { "Application 2", "Application 3" } }};
private void MarketChanged(string value)
{
if (applicationSelector is null)
{
return;
}
applicationSelector.Clear();
if (marketApplications.ContainsKey(value))
{
foreach (string app in marketApplications[value])
{
applicationSelector.Items.AddRange(marketApplications[value]); // This doesn't work as Items is readonly
}
}
}
What's the proper way to do this?

Since you are already using dictionary for the applications MudSelect, we could use the selected market value as key to this dictionary which will then populate only the application options list for that market.
Additionally you need a callback when the market value is changed, you update the selected market and reset the selected application.
Working code:
#page "/"
<MudSelect Class="pa-4" T="string" Label="Market" ValueChanged="SelectedValue">
#foreach (var market in markets)
{
<MudSelectItem T="string" Value="#market">#market</MudSelectItem>
}
</MudSelect>
<MudSelect Class="pa-4" T="string"
Label="Application"
#bind-Value="selectedApplication">
#foreach (var market in marketApplications[selectedMarket])
{
<MudSelectItem T="string" Value="#market">#market</MudSelectItem>
}
</MudSelect>
#code {
string selectedMarket = "Market 1";
string selectedApplication { get;set; }
List<string> markets = new List<string> { "Market 1", "Market 2" };
private Dictionary<string, List<string>> marketApplications { get; } = new()
{
{ "Market 1", new List<string> { "Application 1" } },
{ "Market 2", new List<string> { "Application 2", "Application 3" } }
};
private void SelectedValue(string selectedValue)
{
selectedMarket = selectedValue;
selectedApplication = string.Empty; // reset
}
}
Online Demo:
https://try.mudblazor.com/snippet/wuwcvFOtzhdepIyL
Output:

Related

How to serialize a tree of objects with YamlDotNet

I have the following class:
public class MenuItem
{
public string Title { get; set; }
public List<MenuItem> Items { get; set; }
public MenuItem()
{
Items = new List<MenuItem>();
}
}
How it is possible to properly serialize this?
Adrian Tarniceru
and I created a tree of MenuItem objects and wanted to serialize it with YamlDotNet but the result was unexpected.
MenuItem _root = new MenuItem() { Title = "Menu" };
MenuItem childItem1 = new MenuItem() { Title = "Child item #1" };
childItem1.Items.Add(new MenuItem() { Title = "Child item #1.1" });
childItem1.Items.Add(new MenuItem() { Title = "Child item #1.2" });
_root.Items.Add(childItem1);
_root.Items.Add(new MenuItem() { Title = "Child item #2" });
var serializer = new Serializer();
string fileContent = serializer.Serialize(_root);
using (StreamWriter writer = new StreamWriter("Menu.yaml"))
{
writer.Write(fileContent);
}
result was:
...
bu I expected a tree of MenuItems in Yaml.

ASP.Net MVC - cannot set value of #Html.Checkbox after changing dropdownlist

I've looking all over for something similar, couldn't find nothing..
I'm using ASP.NET MVC 4. I'm building a page so the users in my app can manage the permissions associated with each role.
So i have a view with #htmlDropDownList to show all the available roles, and below, one #Html.CheckBox for each Permission of the role wich is selected above.
The first time the view is rendered, the checkboxes are all set to true or false, according to the permission of that role.All is fine, life is good :) . When the value of the drop is changed, i post the SelectedRoleId using $.ajax. Then, i fetch all the permissions of the new selected role.
While in debug, in the razor view, i can confirm the new values (true or false) inside the model are correct. The problem is that the checkboxes show the old values, before the role was changed..
This is my first question asked, so i'll have to apologize if the question is not being made the best way.
And thx in advance to all of you :)
So here's my Controller:
public ActionResult Index(int ? SelectedRoleId)
{
ManagePermissionsViewModel model = new ManagePermissionsViewModel();
if (SelectedRoleId == null)
{
model.SelectedRoleID = 1; // value 1 is the supervisor Role
}
else
{
model.SelectedRoleID = SelectedRoleId;
}
//values for the dropdownlist of Roles
var items = from x in db.UserRoles
select x;
model.RoleList = new SelectList(items, "Id", "DESCRIPTION");
//gets all the permissions of the selected role
model.EntirePermissionList = (from k in db.Permissions
select new Permission
{
IdPermission = k.Id,
PermissionDescription = k.Description,
IsSet = db.RolePermissions.Any(n => n.RoleId == model.SelectedRoleID && n.PermissionId == k.Id),
PermissionGroupId = (int)k.PermissionGroupId
}).ToList();
//Gets all the groups of Permissions
model.ListPermissionGroups = (from l in db.PermissionGroups
select new PermissionGroup
{
Id = l.Id,
Description = l.Description
}).ToList();
return View(model);
}
[HttpPost]
public ActionResult Index(FormCollection form) {
switch (form["SubmitButton"])
{
case "Save":
SavePermissions();
break;
default:
return RedirectToAction("Index", new RouteValueDictionary(new { controller = "ManagePermissions", action = "Index", SelectedRoleId = Convert.ToInt32(form["SelectedRoleId"]) }));
}
return View();
}
And here is my View:
'#model AML.Web.Models.ManagePermissionsViewModel
#using (Html.BeginForm("Index", "ManagePermissions", FormMethod.Post, new { id = "MyForm" }))
{
#Html.Label("Role :", htmlAttributes: new { #class = "control-label col-md-2" })
#Html.DropDownList("RoleId", Model.RoleList, new { id = "RoleId" })
<div>
#foreach (var item in Model.ListPermissionGroups)
{
<h3> #item.Description</h3>
foreach (var permission in Model.EntirePermissionList.Where(n => n.PermissionGroupId == item.Id))
{
<h5>
#permission.PermissionDescription
#Html.CheckBox("Chk_Permisssion", permission.IsSet)
</h5>
}
}
</div>
<input type="submit" value="Save" name="SubmitButton" class="btn btn-default" />
}
#section Scripts {
<script type="text/JavaScript">
$(document).ready(function () {
$("#RoleId").change(function (e) {
e.preventDefault();
$.ajax({
url: "/ManagePermissions/Index",
cache: false,
type: "POST",
data: { 'SelectedRoleId': $(this).val() },
dataType: "json",
success: function (result) { console.log("Sucess!"); },
error: function (error) { console.log("Error!"); }
})
});
});
</script>
}
And my viewModel:
public class ManagePermissionsViewModel
{
public int? SelectedRoleID { get; set; }
public string SelectedRoleDescription { get; set; }
public SelectList RoleList { get; set; }
public List<Permission> EntirePermissionList { get; set; }
public List<PermissionGroup> ListPermissionGroups { get; set; }
}
public class Permission
{
public int IdPermission { get; set; }
public bool IsSet { get; set; }
public string PermissionDescription { get; set; }
public int PermissionGroupId { get; set; }
}
public class PermissionGroup {
public int Id { get; set; }
public string Description{ get; set; }
}
UPDATE 1 -
Well, i think i got it. Let me post my approach
In the View:
#Html.DropDownListFor(n => n.SelectedRoleID, Model.RoleList,null,
new { onchange = "document.location.href = '/ManagePermissions/Index?SelectedRoleId=' + this.options[this.selectedIndex].value;" })
<div>
#foreach (var item in Model.ListPermissionGroups)
{
<h3> #item.Description</h3>
foreach (var permission in Model.EntirePermissionList.Where(n => n.PermissionGroupId == item.Id))
{
<h5>
#permission.PermissionDescription
<input type="checkbox" id="#permission.IdPermission" checked="#permission.IsSet">
</h5>
}
}
</div>
And in the Controller:
public ActionResult Index(int? SelectedRoleId)
{
ManagePermissionsViewModel model = new ManagePermissionsViewModel();
ModelState.Clear();
if (SelectedRoleId == null)
{
model.SelectedRoleID = 1;
}
else
{
model.SelectedRoleID = SelectedRoleId;
}
var items = from x in db.UserRoles
select x;
model.RoleList = new SelectList(items, "Id", "DESCRIPTION");
model.EntirePermissionList = (from k in db.Permissions
select new Permission
{
IdPermission = k.Id,
PermissionDescription = k.Description,
IsSet = db.RolePermissions.Any(n => n.RoleId == model.SelectedRoleID && n.PermissionId == k.Id),
PermissionGroupId = (int)k.PermissionGroupId
}).ToList();
model.ListPermissionGroups = (from l in db.PermissionGroups
select new PermissionGroup
{
Id = l.Id,
Description = l.Description
}).ToList();
ModelState.Clear();
return View(model);
}
Now each time the Drop changes value, the permissions in the checkboxes are updated. I got it to work with the attribute on the drop, "on change = Document.location.hef = URL". Is this a good approach? Or should i use something like ajax request ?
UPDATE 2
The Controller:
public async Task<ActionResult> Index(int? SelectedRoleId)
{
if (SelectedRoleId == null)
{
SelectedRoleId = 1;
}
var model = await GetSelectedPermissions(SelectedRoleId);
return this.View("Index",model);
}
[HttpGet]
public async Task<ActionResult> GetPermissions(string Id)
{
var SelectedRoleId = int.Parse(Id);
var model = await this.GetSelectedPermissions(SelectedRoleId);
return PartialView("_ManagePermissions", model);
}
private async Task<ManagePermissionsViewModel> GetSelectedPermissions(int? SelectedRoleId)
{
ModelState.Clear();
ManagePermissionsViewModel model = new ManagePermissionsViewModel();
model.SelectedRoleID = SelectedRoleId;
var items = from x in db.UserRoles
select x;
model.RoleList = new SelectList(items, "Id", "DESCRIPTION");
model.EntirePermissionList = await (from k in db.Permissions
select new Permission
{
IdPermission = k.Id,
PermissionDescription = k.Description,
IsSet = db.RolePermissions.Any(n => n.RoleId == model.SelectedRoleID && n.PermissionId == k.Id),
PermissionGroupId = (int)k.PermissionGroupId
}).ToListAsync();
model.ListPermissionGroups = await (from l in db.PermissionGroups
select new PermissionGroup
{
Id = l.Id,
Description = l.Description
}).ToListAsync();
return model;
}
The View
<h2>Permissions - Ajax with Partial View</h2>
#using (Html.BeginForm("SaveData", "ManagePermissions", FormMethod.Post, new { id = "MyForm" }))
{
#Html.Label("Role :", htmlAttributes: new { #class = "control-label col-md-2" })
#Html.DropDownListFor(n => n.SelectedRoleID, Model.RoleList, null, null)
<div id="target">
#Html.Partial("~/Views/Shared/_ManagePermissions.cshtml", Model)
</div>
<input type="submit" value="Save" name="SubmitButton" class="btn btn-default" />
}
#section Scripts {
<script type="text/javascript">
$(document).ready(function () {
$("#SelectedRoleID").change(function () {
var SelectedRoleID = $("#SelectedRoleID").val();
$("#target").load('#(Url.Action("GetPermissions","ManagePermissions",null, Request.Url.Scheme))?Id=' + SelectedRoleID);
});
});
</script>
}
And the Partial View:
<div>
#foreach (var item in Model.ListPermissionGroups)
{
<h3> #item.Description</h3>
foreach (var permission in Model.EntirePermissionList.Where(n => n.PermissionGroupId == item.Id))
{
<h5>
#permission.PermissionDescription
<input type="checkbox" id="#permission.IdPermission" checked="#permission.IsSet">
</h5>
}
}
</div>

MVC 4 multiple buttons in form - why isn't this code working

I am trying to use a variation of the code from this page:
Multiple button in MVC
But everytime I click on the buttons it goes to the index actionresult method and not one of the button methods. Index is the view name but the button clicks are happening in a partial view called "P_NewPersonForm.cshtml"
P_NewPersonForm.cshtml
#using (Html.BeginForm())
{
<div id="divClaimType">
#Html.Label("Claim type:")
#Html.DropDownListFor(m => m.modelClaim.ClaimType, new List<SelectListItem>
{
new SelectListItem{ Text="Legal", Value = "Legal" },
new SelectListItem{ Text="Immigration", Value = "Immigration" },
new SelectListItem{ Text="Housing", Value = "Housing" }
})
</div>
<div id="divClaimStatus" style="padding: 5px;">
#foreach(var item in Model.LinkerStatusOfClaim)
{
#Html.Label("Claim status:")
#Html.DropDownListFor(m => m.LinkerStatusOfClaim[0].ClaimStatusID, new SelectList(Model.modelClaimStatus, "ClaimStatusID", "ClaimStatus"))
#Html.LabelFor(m => m.LinkerStatusOfClaim[0].Notes)
#Html.TextAreaFor(m => m.LinkerStatusOfClaim[0].Notes)
#Html.LabelFor(m => m.LinkerStatusOfClaim[0].StartDate)
#Html.TextBoxFor(m => m.LinkerStatusOfClaim[0].StartDate, new { #id = "datepicker", #Value = DateTime.Now, #readonly = true, Style = "background:#cccccc;" })
<br />
#Html.ValidationMessageFor(model => model.LinkerStatusOfClaim[0].StartDate)
<br />
}
<input type="submit" value="Add another status to this claim..." name="action:add"/>
<input type="submit" value="Delete status." name="action:remove"/>
#* #Ajax.ActionLink("Add another status to this claim...", "AddClaim", "Client", new AjaxOptions { HttpMethod = "POST"})*#
</div>
}
</div>
I have one button for adding to the collection of claims and another to remove one from the collection.
ClientController
public ActionResult Index()
{
var Model = new modelPersonClaim();
// Add one item to model collection by default
LinkerStatusOfClaim LinkerStatusOfClaim = new LinkerStatusOfClaim();
Model.LinkerStatusOfClaim.Add(LinkerStatusOfClaim);
DataLayer.RepositoryClient RC = new RepositoryClient();
Model.isValidModel = true;
RC.GetClaimTypes(Model, PersonTypes.NewPerson.ToString());
return View(Model);
}
[HttpPost]
public ActionResult P_NewPersonForm(modelPersonClaim Model)
{
DataLayer.RepositoryClient RC = new RepositoryClient();
RC.GetClaimTypes(Model, PersonTypes.NewPerson.ToString());
Model.isValidModel = ModelState.IsValid;
if (ModelState.IsValid)
{
RC.CreatePerson(Model);
Model.SuccessfulInsert = true;
Model.InsertString = "Person data has been successfully inserted into the database.";
if (Model.modelClaim.ClaimMade)
{
RC.CreateClaim(Model);
}
}
else
{
Model.SuccessfulInsert = false;
Model.InsertString = "Person data could not be inserted into the database. Missing key fields.";
}
return View("Index", Model);
}
[AttributeUsage(AttributeTargets.Method, AllowMultiple=false, Inherited = true)]
public class MultiButtonAttribute : ActionNameSelectorAttribute
{
public string Name { get; set; }
public string Argument { get; set; }
public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
{
var isValidName = false;
var keyValue = string.Format("{0}:{1}", Name, Argument);
var value = controllerContext.Controller.ValueProvider.GetValue(keyValue);
if (value != null)
{
controllerContext.Controller.ControllerContext.RouteData.Values[Name] = Argument;
isValidName = true;
}
return isValidName;
}
}
[HttpPost]
[MultiButtonAttribute(Name = "action", Argument = "Add another status to this claim...")]
public ActionResult AddClaimStatus(modelPersonClaim Model)
{
Model.LinkerStatusOfClaim.Insert(Model.LinkerStatusOfClaim.Count, new LinkerStatusOfClaim());
return View("Index", Model);
}
[HttpPost]
[MultiButtonAttribute(Name = "action", Argument = "Delete status.")]
public ActionResult RemoveClaimStatus(modelPersonClaim Model)
{
// Can't remove IF only 1
if (Model.LinkerStatusOfClaim.Count == 1)
{
}
else
{
Model.LinkerStatusOfClaim.RemoveAt(Model.LinkerStatusOfClaim.Count);
}
return View("Index", Model);
}
When I click one the buttons it hits the public override bool IsValidName twice. Once for each button. But then because the action name is always index, it goes to the index method and not one of the button methods.
Does anyone have any ideas how to fix this?
Something is wrong with this part:
var keyValue = string.Format("{0}:{1}", Name, Argument);
var value = controllerContext.Controller.ValueProvider.GetValue(keyValue);
Your attribute is this:
[MultiButtonAttribute(Name = "action", Argument = "Add another status to this claim...")]
So in that case keyValue will become: "action:Add another status to this claim..." while your HTML states: <input type="submit" value="Add another status to this claim..." name="action:add"/>, so I think Argument in your attribute should be add.

MVC 4 WebGrid DropDownLIstFor selectedValue

I have a web grid in a partial view. Each column has a display and edit mode. The display mode uses labels to display the data. When a user selects "Edit", the display mode is hidden and the edit mode is displayed. Everything works, except for the "selectValue:" in the DropDownListFor in column two. The DDLF displays the selectlist, but starts with the first value instead of using the selectedValue. I've tried every variation I can come up with. Any ideas? Thanks for taking a look at this.
#model ANet.Areas.IMS.Models.DVModel
#using System.Web.Helpers
#{var grid = new WebGrid(Model.DMRN);}
<div id="gridMRN" style=" padding:20px; " >
#grid.GetHtml(
tableStyle: "webgrid-table",
headerStyle: "webgrid-header",
footerStyle: "webgrid-footer",
alternatingRowStyle: "webgrid-alternating-row",
selectedRowStyle: "webgrid-selected-row",
rowStyle: "webgrid-row-style",
mode: WebGridPagerModes.All,
columns:
grid.Columns(
grid.Column("PK_ID", "MRN ID", format: #<text><span class="display-mode">#item.PK_ID</span><label id="lblPK_ID" class="edit-mode">#item.PK_ID</label><input type="hidden" name="PK_ID" id="PK_ID" value="#item.PK_ID" /><input type="hidden" name="fk_ID" id="fk_ID" value="#item.fk_ID" /> </text>),
grid.Column("fk_MFID", "MF", format: #<text><span class="display-mode"><label id="lblfk_MFID">#item.v_L_MF.MFN</label></span>#Html.DropDownListFor(m => m.fk_MFID, new SelectList(Model.L_MF, "Value", "Text", item.fk_MFID), new { #class = "edit-mode" })</text>, style: "webgrid-col1Width"),
grid.Column("MRN", "MRN", format: #<text> <span class="display-mode"><label id="lblMRN">#item.MRN</label></span><input type="text" id="MRN" value="#item.MRN" class="edit-mode" /></text>, style: "webgrid-col3Width"),
grid.Column("Action", format: #<text>
<button class="edit-MRN display-mode" >Edit</button>
<button class="save-MRN edit-mode" >Save</button>
<button class="cancel-MRN edit-mode" >Cancel</button>
</text>, style: "webgrid-col3Width" , canSort: false)))
</div>
<script type="text/javascript" >
$(function () {
$('thead tr th:nth-child(1), tbody tr td:nth-child(1)').hide();
$('.edit-mode').hide();
$('.edit-MRN, .cancel-MRN').on('click', function () {
var tr = $(this).parents('tr:first');
tr.find('.edit-mode, .display-mode').toggle();
$("#MRNAddFrm").toggle();
});
$('.save-MRN').on('click', function () {
var tr = $(this).parents('tr:first');
var PK_ID = tr.find("#PK_ID").val();
var fk_ID = tr.find("#fk_ID").val();
var fk_MFID = tr.find("#fk_MFID").val();
var MRN = tr.find("#MRN").val();
tr.find("#lblPK_ID").text(PK_ID);
tr.find("#lblfk_ID").text(fk_ID);
tr.find("#lblfk_MFID").text(fk_MFID);
tr.find("#lblMRN").text(MRN);
tr.find('.edit-mode, .display-mode').toggle();
var MRM =
{
"PK_ID": PK_ID,
"fk_ID": fk_ID,
"fk_MFID": fk_MFID,
"MRN": MRN
};
$.ajax({
url: '/IMS/EditMRN/',
datatype: 'json',
data: JSON.stringify(MRN),
type: 'POST',
contentType: 'application/json; charset=utf-8'
})
.success(function (data) {
$('#gridMRN').replaceWith(data);
});
$("#MRNAddFrm").toggle();
});
})
</script>
ViewModel
using IMSModel;
namespace ANet.Areas.IMS.Models
{
public class DVModel
{
private IMSEntities db = new IMSEntities();
public DVModel()
{
//Define default values here
this.PageSize = 10;
this.NumericPageCount = 10;
}
....
[Display(Name = "MF")]
public int fk_MFID { get; set; }
[Display(Name = "MRN")]
public Nullable<int> MRN { get; set; }
....
public SelectList L_MF { get; set; }
..... other selectlists
public IEnumerable<v_L_MF> v_L_MF { get; set; }
..... other ienumerables lists
//Sorting-related properties
public string SortBy { get; set; }
public bool SortAscending { get; set; }
public string SortExpression //requires using System.Linq.Dynamic; on the controller
{
get
{
return this.SortAscending ? this.SortBy + " asc" : this.SortBy + " desc";
}
}
//Paging-related properties
public int CurrentPageIndex { get; set; }
public int PageSize { get; set; }
public int PageCount
{
get
{
return Math.Max(this.TotalRecordCount / this.PageSize, 1);
}
}
public int TotalRecordCount { get; set; }
public int NumericPageCount { get; set; }
}
}
Method that loads the view model
private DVModel GetDVModel(int id)
{
var _viewModel = new DVModel
{
.... other lists
v_L_MF = unitOfWork.MFRepository.Get().OrderBy(o => o.MFN),
.... other lookup lists
L_MF = new SelectList(unitOfWork.MFRepository.Get().OrderBy(o => o.MFN), "PK_MFID", "MFN", String.Empty),
};
return _viewModel;
}
Your DropdownlistFor calling will the issue.
Please lets check the follwing site.
You should give the default value on dropdownlist level, and not on select list level.
I dont remember correctly the real calling but something like this should be tryied:
#Html.DropDownListFor(m => m.fk_MFID, new SelectList(Model.L_MF, "Value", "Text", item.fk_MFID), new { #class = "edit-mode" }, "Default value")

RavenDB static index on dictionary

I have an application that uses documents, that contain list of attributes in a dictionary, for some reason we need to use a static index and query/filter over these attributes.
A prototype looks like this:
class Program
{
static void Main(string[] args)
{
IDocumentStore store = new DocumentStore() { DefaultDatabase = "Test", Url = "http://localhost:8081" };
store.Initialize();
IndexCreation.CreateIndexes(typeof(Program).Assembly, store);
using (var session = store.OpenSession())
{
session.Store(new Document { Id = "1", Name = "doc_name", Attributes = new Dictionary<string, object> { { "Type", "1" }, { "Status", "Active" } } });
session.SaveChanges();
}
using (var session = store.OpenSession())
{
// works
var l1 = session.Query<Document, Documents_Index>().Where(a => a.Attributes["Type"] == "1").ToList();
// not working
var l2 = session.Query<Document, Documents_Index>().Where(a => a.Attributes["Status"] == "Active").ToList();
}
}
}
public class Documents_Index : AbstractIndexCreationTask<Document>
{
public Documents_Index()
{
Map = docs => docs.Select(a =>
new
{
a.Name,
a.Attributes,
Attributes_Type = a.Attributes["Type"]
});
}
}
[Serializable]
public class Document
{
public string Id { get; set; }
public string Name { get; set; }
public Dictionary<string, object> Attributes { get; set; }
}
But since I need to query using any arbitrary Attribute name/value this index does solve our problem. Actually the list of attributes is known at run-time (so we tried modifying the Map expression to inject any number of attribute names, but so far we weren't successful). Is there a way how to define the index in some dynamic fashion?
You need to write it like:
public class Documents_Index : AbstractIndexCreationTask<Document>
{
public Documents_Index()
{
Map = docs => docs.Select(a =>
new
{
a.Name,
_ = a.Attributes.Select(x=>CreateField("Attributes_"+x.Key, x.Value),
});
}
}