How to do two-way binding on a radio button Blazor child component - radio-button

I'm trying to create a radio button component in Blazor that has two way data binding but I can't seem to get the value (testNumber) on the parent to change. I am new to Blazor and C#, so any help would be greatly appreciated. Thanks
ChildComp.razor
<div>
<label for="radio1">1</label>
<input
id="radio1"
type="radio"
value="1"
name="test"
checked="#(_selectedGroup == 1)"
#onclick="#(() => _selectedGroup = 1)"/>
<label for="radio2">2</label>
<input
id="radio2"
type="radio"
value="2"
name="test"
checked="#(_selectedGroup == 2)"
#onclick="#(() => _selectedGroup = 2)"/>
</div>
#code {
private int _selectedGroup = 0;
[Parameter]
public int BindingValue
{
get => _selectedGroup;
set
{
if (_selectedGroup == value )
{
return;
}
else
{
_selectedGroup = value;
}
BindingValueChanged.InvokeAsync(value);
}
}
[Parameter]
public EventCallback<int> BindingValueChanged { get; set; }
}
ParentComp.razor
<div>
<ChildComp #bind-BindingValue="testNumber" />
<h5>#testNumber</h5>
</div>
#code {
int testNumber = 0;
}

As you probably noticed bind does not work with radio buttons. On GitHub you can see the discussion about it here. It's sad that Blazor doesn't support these simple features...
I had the same problem and came across this solution:
#code {
public int EditionCode = 1;
// "Edition" class has "int Code" and "string Text" properties.
public Edition[] Editions = new [] {
new Edition { Code = 1, Text = "Home" },
new Edition { Code = 2, Text = "Pro" },
new Edition { Code = 3, Text = "Enterprise" },
};
}
#foreach (var edition in this.Editions)
{
<label>
<input type="radio"
name="edition"
checked="#(EditionCode == edition.Code)"
onchange="#(() => EditionCode = edition.Code)"/>
#edition.Text
</label>
}
If this solution doesn't solve your needs, then have a look here (a bit more complex).

Related

Blazor Server - How to disable a control inside component?

I try to show and disable a button by adding "disabled" class in a component (pre-hidden) but failed - it's not working. Where I did wrong ?
Component Button :
<div class="form-group">
<button class="btn btn-primary #disabled">Disable Me</button>
</div>
#code {
string _password;
string disabled = "";
public void Disable()
{
disabled = "disabled";
}
}
Index.razor :
#page "/"
<h1>How to disable button in component ?</h1>
<button class="btn btn-primary" #onclick="ShowAndDisableButton">Show and disable button</button>
#if (show)
{
<ButtonComponent #ref="button"/>
}
#code
{
ButtonComponent button = new();
bool show = false;
void ShowAndDisableButton()
{
show = true;
button.Disable();
}
}
UPDATED : if I change the ShowAndDisableButton code to
async Task ShowAndDisableButton()
{
show = true;
await Task.Delay(TimeSpan.FromMilliseconds(10)); // add this, wait for a while
button.Disable();
}
and change button code in index.razor to
<button class="btn btn-primary" #onclick="()=>ShowAndDisableButton()">Show and disable button</button>
it works. but I don't know why and don't want to use such way, are there any proper way?
The problem is that button.Disable(); does not cause the normal rerendering.
And it is an overcomoplicated way of doing things.
In the page:
#if (show)
{
<ButtonComponent Disabled="!show" />
}
#code
{
//ButtonComponent button = new();
bool show = false;
void ShowAndDisableButton()
{
show = true;
//button.Disable();
}
}
and the button itself:
<div class="form-group">
<button class="btn btn-primary" disabled="Disabled">Disable Me</button>
</div>
#code {
string _password;
// string disabled = "";
[Parameter] public bool Disabled {get; set; }
}
But you won't be able to use this button.
Use disabled="#disabledState"
Where disabledState is a boolean

MVC checkbox list bounding to model

I am trying to collect all the options that the user have selected for a checkbox list. The checkbox list is built using a foreach loop and I have a int[] that I am trying to put the id into. Any help would be great.
View
#{
int idxFormats = 0;
foreach (var item in Model.ListOfFormats)
{
<div class='col-md-6'>
<input type="checkbox" value=#item.Value name="chkFormat" />
<label asp-for=#item.Selected>#Html.Raw(#item.Name)</label>
#Html.HiddenFor(m => Model.selectedFormats[idxFormats]);
</div>
idxFormats++;
}
#Html.ValidationMessageFor(model => model.selectedFormats[idxFormats])
}
Model
public List<GenericValues> ListOfFormats { get; set; }
[Display(Name = "At least one 'Format' must be selected")]
public int[] selectedFormats { get; set; }
Change the Checkbox name to selectedFormats
<input type="checkbox" value=#item.Value name="selectedFormats" />
Test example:
Model:
public class Test
{
public List<GenericValues> ListOfFormats { get; set; }
public int[] selectedFormats { get; set; }
}
public class GenericValues
{
public int Value { get; set; }
public string Name { get; set; }
public bool Selected { get; set; }
}
View:
#model Test
#{
ViewData["Title"] = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1>Index</h1>
<form method="post">
#{
foreach (var item in Model.ListOfFormats)
{
<div class='col-md-6'>
<input type="checkbox" value=#item.Value name="selectedFormats" />
<label asp-for=#item.Selected>#Html.Raw(#item.Name)</label>
</div>
}
}
<input type="submit" value="submit" />
</form>
Controller:
public IActionResult Index()
{
Test test = new Test
{
ListOfFormats = new List<GenericValues>
{
new GenericValues
{
Name = "A",
Value = 1,
},
new GenericValues
{
Name = "B",
Value = 2,
},
new GenericValues
{
Name = "C",
Value = 3,
}
}
};
return View(test);
}
[HttpPost]
public IActionResult Index(Test test)
{
return Ok();
}
Result:
if you are looking to put id as value of your idxFormats then use this code in your checkbox:
<input type="checkbox" value=#item.Value name="chkFormat" id="#idxFormats" />
Edit:
I am not so familiar with c#, I tested with minimum code :
// Replace the model correct path by yours
#model IEnumerable<WebApplication1.Models.MyModels.ListOfFormats>
#{
int idxFormats = 0;
foreach (var item in Model)
{
<div class='col-md-6'>
<input type="checkbox" value=#item.Value name="chkFormat" id="#idxFormats"/>
<label>#Html.Raw(#item.Name)</label>
</div>
idxFormats++;
}
}

How to implement the inline editing for this grid using devexpress blazor

I have a created a grid using devexpress blazor. I want to implement an inline editing for this grid, although devexpress haven't implemented any inline editing functionality.
Here is ht code i have used for this Grid.
#if (dischargeBoards == null)
{
<p><em>Loading...</em></p>
}
else
{
<div class="card demo-card-wide border-bottom-0">
<div class="card-header border-bottom-0">
ClientVisitGuid: <b>#(selectedRow == null ? (object)"(none)" : selectedRow.ClientVisitGuid)</b>
CurrentLocationGUID: <b>#(selectedRow == null ? (object)"(none)" : selectedRow.CurrentLocationGUID)</b>
PatientName: <b>#(selectedRow == null ? "(none)" : selectedRow.PatientName)</b>
</div>
</div>
<DxDataGrid Data="#dischargeBoards"
ShowFilterRow="false"
#bind-SingleSelectedDataRow="#SelectedRow"
        
        ShowPager="true"
        ShowGroupPanel="true"
        PageSize="19">
<DxDataGridColumn Field="#nameof(DischargeBoardVisit.LocationGroup)" Caption="L/C Group" AllowGroup="true"></DxDataGridColumn>
<DxDataGridColumn Field="#nameof(DischargeBoardVisit.Location)" Width="100px"></DxDataGridColumn>
<DxDataGridColumn Field="#nameof(DischargeBoardVisit.PatientName)" SortIndex="0" Width="240px"></DxDataGridColumn>
<DxDataGridColumn Field="#nameof(DischargeBoardVisit.Service)" Width="240px"></DxDataGridColumn>
<DxDataGridDateEditColumn Field="#nameof(DischargeBoardVisit.DischargeDateExp)"
                 DisplayFormatString="MM/dd/yyyy"
                 EditFormatString="d"></DxDataGridDateEditColumn>
<DxDataGridColumn Field="#nameof(DischargeBoardVisit.DischargeTimeExp)" Caption="Time Exp"></DxDataGridColumn>
<DxDataGridColumn Field="#nameof(DischargeBoardVisit.Family)" Caption="Family">
<DisplayTemplate>
#{
var checkboxFamily = (context as DischargeBoardVisit).Family;
if (checkboxFamily)
{
<button class="btn btn-success btn-circle btn-circle-sm m-1">#*<i class="fa fa-check"></i>*#</button>
}
else
{
<button class="btn btn-danger btn-circle btn-circle-sm m-1"></button>
}
}
</DisplayTemplate>
</DxDataGridColumn>
<DxDataGridColumn Field="#nameof(DischargeBoardVisit.Rehab)">
<DisplayTemplate>
#{
var checkboxRehab = (context as DischargeBoardVisit).Rehab;
//<input type="checkbox" checked="#checkboxRehab" disabled readonly />
if (checkboxRehab)
{
<button class="btn btn-success btn-circle btn-circle-sm m-1">#*<i class="fa fa-check"></i>*#</button>
}
else
{
<button class="btn btn-danger btn-circle btn-circle-sm m-1"></button>
}
}
</DisplayTemplate>
</DxDataGridColumn>
<DxDataGridColumn Field="#nameof(DischargeBoardVisit.Comment)" Width="240px"></DxDataGridColumn>
</DxDataGrid>
}
#code {
DischargeBoardVisit[] dischargeBoards;
// readonly string _id = Guid.NewGuid().ToString();
[Parameter]
public string DisplayFormatString { get; set; }
protected override async Task OnInitializedAsync()
{
dischargeBoards = await DischageBoard.GetDischargeAsync();
SelectedRow = dischargeBoards.FirstOrDefault();
}
public DischargeBoardVisit context { get; set; }
DischargeBoardVisit selectedRow;
public DischargeBoardVisit SelectedRow
{
get
{
return selectedRow;
}
set
{
selectedRow = value;
InvokeAsync(StateHasChanged);
}
}
}
I haved tried in different ways. But i couldn't find any proper solution for that.
thanks in advance. All appreciation would be highly appreciated.
Currently, there is no straightforward way to do so. That's why I suggest that you wait until this feature is implemented since it is in the Backlog of the DevExpress Blazor team. Please follow the updates in the blogs.

Model passed to form in partialview returns with components (that were not null before calling form) being null on form post to controller

I have been trying to find out why submitting a form in my partialview makes some components of my model null. Just before calling the partialview, I have a model with count of AgainstWhoms and TimesPlaces each equal to one.
Even with a simplified partialview where only a column is added, on submitting to the controller, my AgainstWhoms and TimesPlaces collections are now null.
public class ComplaintViewModel
{
[Key]
public int Id { get; set; }
.........
public List<AgainstWhomViewModel> AgainstWhoms { get; set; }
public List<TimesPlacesViewModel> TimesPlaces { get; set; }
public List<WitnessesViewModel> Witnesses { get; set; }
}
public async Task<ActionResult> GetNewComplaint(int intComplainantId)
{
var complaint = new ComplaintViewModel
{
ComplainantId = intComplainantId,
StatusId = 1,
ReceivedDate = DateTime.Now,
AgainstWhoms = new List<AgainstWhomViewModel> { },
TimesPlaces = new List<TimesPlacesViewModel> { },
Witnesses = new List<WitnessesViewModel> { }
};
var newtime = new TimesPlacesViewModel { IncidentDate = DateTime.Today, IncidentLocation = "aaaaaaaaa" };
complaint.TimesPlaces.Add(newtime);
var complainee = new AgainstWhomViewModel { CountryId = 1, Email = "aaaaaaa#yahoo.com"};
complaint.AgainstWhoms.Add(complainee);
..................
return PartialView("_ComplaintFormModal", complaint);
}
Below is my simplified view.
#model ComplaintViewModel
<div>
<form id="Complaintform" asp-controller="Complaint" asp-action="RegisterComplaint" method="post">
<div class="form-row">
<div class="form-group col-lg-8 required">
<label asp-for="ComplaintTitle" class="control-label"></label>
<input type="text" class="form-control" required asp-for="ComplaintTitle">
<span asp-validation-for="ComplaintTitle" class="text-danger"></span>
</div>
</div>
<button type="submit" value="Submit">Submit</button>
</form>
</div>
In my controller post method, newComplaint.AgainstWhom and newComplaint.TimePlaces are now null, while other fields that do not belong to any of the linked lists are returned correctly:
[HttpPost]
public ActionResult RegisterComplaint(ComplaintViewModel newComplaint)
{
..............
You didn't render the TimesPlaces/AgainstWhoms so that data will lose since they are not in form collection .
If you want to edit the TimesPlaces/AgainstWhoms items , you can render like :
#for (int i = 0; i < Model.TimesPlaces.Count; i++)
{
<tr>
<td>
#Html.TextBoxFor(model => model.TimesPlaces[i].IncidentDate)
</td>
<td>
#Html.TextBoxFor(model => model.TimesPlaces[i].IncidentLocation)
</td>
</tr>
}
If you don't want to edit them , you can use hidden field :
#for (int i = 0; i < Model.TimesPlaces.Count; i++)
{
#Html.HiddenFor(model => model.TimesPlaces[i].IncidentDate)
#Html.HiddenFor(model => model.TimesPlaces[i].IncidentLocation)
}
But it's better to avoid that . If you don't want to edit them , i would prefer to query database with ID again for up-to-date records , and avoid posting large data in a request .

C# MVC API send values using GET queryString?

This is first time I have tried to make an API using MVC4. So far it is working ok.
For practice I want to try and send my model using a queryString in the GET method instead of my current POST send method.
As I have no clue how to start, and whats need to be done ? Can you come with some advices ?
Can I have the Index view as it is ? or anything need to be changed ?
I also would like to keep the curent GET method I have to show the list, I guess that will interfere if I add a new GET method fot sending querystring ?
All advices is helpful here ^_^
namespace MessageHandler.Models
{
public class Message
{
public int Id { get; set; }
public double Amount { get; set; }
public string PaymentMessage { get; set; }
public string Name { get; set; }
public string Adress { get; set; }
}
}
namespace MessageHandler.Services
{
public class MessageRepository
{
private const string CacheKey = "MessageStore";
public MessageRepository()
{
var ctx = HttpContext.Current;
if (ctx != null)
{
if (ctx.Cache[CacheKey] == null)
{
var messages = new Message[]
{
new Message
{
Id = 1, PaymentMessage = "payment for order 23434",
Name = "Christer Glenning", Adress = "Grenvagen 24",
Amount = 2300
},
new Message
{
Id = 2, PaymentMessage = "payment for order 24354",
Name = "Carl Ingemar", Adress = "Regnbagen 446",
Amount = 44
}
};
ctx.Cache[CacheKey] = messages;
}
}
}
public Message[] GetAllMessages()
{
var ctx = HttpContext.Current;
if (ctx != null)
{
return (Message[])ctx.Cache[CacheKey];
}
return new Message[]
{
new Message
{
Id = 0,
Name = "placeHolder"
}
};
}
public bool SaveMessage(Message message)
{
var ctx = HttpContext.Current;
if (ctx != null)
{
try
{
var currentData = ((Message[])ctx.Cache[CacheKey]).ToList();
currentData.Add(message);
ctx.Cache[CacheKey] = currentData.ToArray();
return true;
}
catch (Exception exp)
{
Console.WriteLine(exp.Message);
return false;
}
}
return false;
}
}
}
using MessageHandler.Models;
using MessageHandler.Services;
namespace MessageHandler.Controllers
{
public class MessageController : ApiController
{
private MessageRepository repo;
public MessageController()
{
this.repo = new MessageRepository();
}
public Message[] Get()
{
return repo.GetAllMessages();
}
public HttpResponseMessage Post(Message message)
{
this.repo.SaveMessage(message);
var response = Request.CreateResponse<Message>(System.
Net.HttpStatusCode.Created, message);
return response;
}
}
}
<header>
<div class="content-wrapper">
<div class="float-left">
<p class="site-title">
API</p>
</div>
</div>
</header>
<div id="body">
<ul id="messages"></ul>
<form id="saveMessageForm" method="post">
<h3>Create a new Message</h3>
<p>
<label for="messageId">Id:</label>
<input type="text" name="Id" />
</p>
<p>
<label for="messagePaymentMessage">Message:</label>
<input type="text" name="PaymentMessage" />
</p>
<p>
<label for="messageName">Name:</label>
<input type="text" name="Name" />
</p>
<p>
<label for="messageAdress">Adress:</label>
<input type="text" name="Adress" />
</p>
<p>
<label for="messageAmount">Amount:</label>
<input type="text" name="Amount" />
</p>
<input type="button" id="saveMessage" value="Save" />
</form>
</div>
#section scripts
{
<script type="text/javascript">
$(function()
{
$.getJSON('/api/message', function (messagesJsonPayload) {
$(messagesJsonPayload).each(function (i, item) {
$('#messages').append('<li>' + item.PaymentMessage + '</li>' +
'<li>' + item.Name + '</li>' +
'<li>' + item.Adress + '</li>' +
'<li>' + '$' + item.Amount.toFixed(2) + '</li>' + '<br>');
});
});
});
</script>
<script type="text/javascript">
$('#saveMessage').click(function()
{
$.post("api/message",
$("#saveMessageForm").serialize(),
function(value)
{
$('#messages').append('<li>' + value.PaymentMessage + '</li>' +
'<li>' + value.Name + '</li>' +
'<li>' + value.Adress + '</li>' +
'<li>' + '$' + value.Amount.toFixed(2) + '</li>');
},
"json"
);
});
</script>
}
Well, I'm not expert for build an API, but I think you need to step back and learning concept for building an API (specially the REST one).
here's the link that maybe useful for you:
build-restful-apis-with-aspnet-web-api
REST API Tutorial