Blazor List Of Strings Input Binding - c#

I'm trying to display a list of strings and I want the user to be able to edit the list to make changes to the object but when I view the list after modifying the input fields the changes haven't been made.
How do I bind a list of strings?
#foreach (var message in UserMessageService.GetSomeData())
{
<tr>
<td><input type="text" bind="#message.Username" value="#message.Username" onblur="SaveMessages"/></td>
<td><input type="text" bind="#message.Message" value="#message.Message" onblur="SaveMessages"/></td>
</tr>
}

Use right Blazor syntax:
<input
type="text" #bind="#message.Message"/>
If you need to execute function on blur:
<input value="#message.Message"
#onchange="#((ChangeEventArgs __e) =>
{ message.Message = __e.Value.ToString());
SaveMessages(); })" />
More info: https://learn.microsoft.com/en-us/aspnet/core/blazor/components?view=aspnetcore-3.0#data-binding

silly mistake on my part, the issue wasn't with my syntax. I made the mistake of binding to my service instead of a local variable so when I left focus it couldn't update and just retrieved from the service
I simply added the local variable below
#foreach (var message in dataVariable)
{
<tr>
<td><input type="text" #bind="message.Username" /></td>
<td><input type="text" #bind="message.Message" /></td>
</tr>
}
#code {
private List<someData> dataVariable;
protected override void OnInitialized()
{
TableSeats = UserMessageService.GetSomeData();
}
}

Related

Load a text file to table in browser, which can be edited and then replace the origin file?

This is through the Blazor Server App.
I have a text file that looks like this:
TEXT00
Some title
TEXT10
8
DATA
110,4,2
110,0,6
110,0,32
110,4,16
110,0,16
110,4,3
110,0,2
...
...
There are two things I want to accomplish:
First I want such a file be loaded on to an editable table, where the numbers under the DATA line should go in each their own editable cell.
Illustration:
Tempo
Length
secs
110
4
2
110
0
6
110
0
32
Secondly I want the content in the cells being able to be saved, such that it replaces the original text file in the directory.
With the press of a button, the file gets loaded in the a cell which is editable with the use of contenteditable="true". I have tried but failed at loading the numbers into their own cells. The save file button doesn't work when it comes to data cells.
Here is the open button, table and save button:
<button #onclick="OpenFile">Open file</button>
<div class="table-wrapper-scroll-y my-custom-scrollbar">
<table class="table table-bordered table-striped mb-0">
<thead class="bg-light">
<tr>
<th>Title: </th>
</tr>
<tr>
<th>Tempo</th>
<th>Length</th>
<th>Secs</th>
</tr>
</thead>
<tbody>
<tr>
<td><div contenteditable="true">#_contents</div> </td>
<td><div contenteditable="true"></div></td>
<td><div contenteditable="true"></div></td>
</tr>
<tr>
<td><div contenteditable="true"></div> </td>
<td><div contenteditable="true"></div></td>
<td><div contenteditable="true"></div></td>
</tr>
</tbody>
</table>
</div>
<button #onclick="SaveFile">Save file</button>
Here are the functions which loads the file and the one which should save the new one.
#code {
string _contents { get; set; } = string.Empty;
void OpenFile()
{
_contents = File.ReadAllText(#"path");
}
void SaveFile()
{
File.WriteAllText(#"path", _contents);
}
}
Does anyone have some knowledge on how to insert the numbers in cells such that when saved, the txt file gets replaced by the edits?
To achive this you'll need to use binding elements. For example:
<input #bind="YourProperty" type="text" />
This needs to be done for each column and every row. The best solution would look something like this:
List<WhateverItem> items = new(); // This list should hold all your objects from your text file
public class WhateverItem
{
public string Tempo { get; set; }
public string Length { get; set; }
public string Secs { get; set; }
}
Then in .razor
#foreach (var item in items)
{
<tr>
<td>
<input #bind="item.Tempo" type="text" />
</td>
<td>
<input #bind="item.Length" type="text" />
</td>
<td>
<input #bind="item.Secs" type="text" />
</td>
</tr>
}
When you save, you'll need to recreate the content out of the objects with a StringBuilder.
If you want to validate the fields, think of using an EditForm. Keep in mind that you can also bind to other types besides of string. You'll need to change the input type then.
Example of parsing the file into objects:
List<WhateverItem> items = new();
foreach (string line in System.IO.File.ReadLines(#"c:\test.txt"))
{
string[] values = line.Split(',');
if(values.Length == 3)
{
// Keep in mind you can also convert to values right here if you want
items.Add(new WhateverItem
{
Tempo = values[0],
Length = values[1],
Secs = values[2]
});
}
}

How can I bind a dynamic-length List<> in a Razor/.NET Core PageModel, without relying on JavaScript to re-index each input?

I have a form in which a user can supply an arbitrary-length list of <DateTime, int> pairs. It is represented like so:
List<ItemsPerDay> ItemsPerDayList = new List<ItemsPerDay>();
public class ItemsPerDay {
public DateTime Date { get; set; }
public int Amount { get; set; }
}
<tbody>
#{ var i = 0; }
#foreach (var _ in Model.ItemsPerDayList) {
<tr>
<td><input asp-for="ItemsPerDayList[i].Date" type="date" /></td>
<td><input asp-for="ItemsPerDayList[i].Amount" /></td>
<td><a class="remove">Remove</a></td>
</tr>
i++;
}
</tbody>
The issue:
The user is able to add/remove rows as they need. However, the property binding relies on the pairs being properly indexed. If, for example, you remove the first item, the list now begins at [1] and the property binding does not work; ItemsPerDayList is posted as null.
My current workaround:
I've had to use some JavaScript to make sure the indexes always remain correct. This works but isn't optimal.
function reIndexItemRows() {
$("table > tbody > tr").each(function(idx) {
$(this).find("input[type=date]").attr({
"data-val": true,
"data-val-required": "The Date field is required.",
id: `ItemsPerDayList_${idx}__Date`,
name: `ItemsPerDayList[${idx}].Date`
});
$(this).find("input[type=number]").attr({
"data-val": true,
"data-val-required": "The Amount field is required.",
id: `ItemsPerDayList_${idx}__Amount`,
name: `ItemsPerDayList[${idx}].Amount`
});
});
}
The question:
What is the appropriate way to represent this model on the front-end, such that I don't have to rely on JavaScript to groom the form each time a row is added or removed?
NOTE: I am not doing any updates, therefore the indexes are not necessary. Upon submission, any existing pairs are deleted, and the form-submitted pairs are inserted.
JavaScript is necessary for adjusting index. You can add events to adjust the index when submitting the form.
Add a event on Remove. Here is the form.
<form method="post" id="myform">
<table>
<tbody>
#{ var i = 0; }
#foreach (var _ in Model.ItemsPerDayList)
{
<tr>
<td><input asp-for="ItemsPerDayList[i].Date" type="date" /></td>
<td><input asp-for="ItemsPerDayList[i].Amount" /></td>
<td><a class="remove" onclick="remove(this)" >Remove</a></td>
</tr>
i++;
}
</tbody>
</table>
<input type="submit" name="name" value="submit" />
</form>
<button id="add" onclick="add()" class="btn-primary">add</button>
Before submitting the form, javascript iterates each row and modify the index.
#section Scripts{
<script>
$('#myform').submit(function () {
var i = 0;
$("tbody> tr ").each(function () {
$(this).find("td input[name$='Date']").attr("name", "ItemsPerDayList[" + i + "].Date");
$(this).find("td input[name$='Amount']").attr("name", "ItemsPerDayList[" + i + "].Amount");
i++
})
// ...
return true; // return false to cancel form action
});
function remove(e) {
$(e).parent().parent().remove()
}
function add() {
$('tbody').append('<tr><td> <input name="ItemsPerDayList[i].Date" type="date" /></td ><td><input name="ItemsPerDayList[i].Amount" /><td><a class="remove" onclick="remove(this)">Remove</a></td></tr>');
}
</script>
}
Then, I can get the all data from front-end.

get values in controller class from html form elements with the same name

In my MVC project, I created a table from a database I made, and added Edit/Save and Delete buttons to interact with the DB accordingly.
I created the code in the cshtml file with razor-notation for loop, which means that my input elements all have the same name (to be called in the controller).
I'm trying to figure out how to single out a specific row and get a specific element, even though there are multiple elements with the same name (number of rows in my table).
snippet of my view:
#{
int i=0;
foreach(link l in Model.links)
{
<tr>
<td><input class="idField" name="link.Id" type="text" value="#l.Id" disabled="disabled" /></td>
<td><input class="linkField" name="link.link" type="text" value="#l.link" disabled="disabled" /></td>
<td><input class="timeField" name="link.Time" type="text" value="#l.Id" disabled="disabled" /></td>
<td>
<input class="edit" type="button" value="Edit" formaction="Update" onclick="enableField(#i)" />
</td>
</tr>
i++;
}
}
Update action in my controller:
public ActionResut Update(){
LinkDal dal = new LinkDal(); /*LinkDal uses Entity framework to connect to my DB*/
List<Link> links = dal.links.ToList<Link>();
Link toUpdate = dal.links.Find(int.Parse(Request.Form["link.Id"].ToString()));
toUpdate.link = Request.Form["link.link"].ToString();
toUpdate.Time = int.Parse(Request.Form["link.link"].ToString());
dal.SaveChanges();
VMLinks vml = new VMLinks();
vml.link = toUpdate;
vml.links = links;
return View("MyView", vml);
}
instead of gettin the specific "link" object, "toUpdate" becomes null because the Request.Form doesn't return anything.
I tried typing an ID that I know it exists and the code works (the DB is updated).
My problem is that I'm not being able to access the text inside the input element because there are multiple elements with the same name (for example - "link.Id").

ASP.NET Core MVC view displaying incorrect values from input in list

I'm building a quotation form in ASP.NET Core MVC Web App. I've got a QuoteVM that contains required properties for the quote plus a List QuoteItems to store dynamically many items on a quote:
public class QuoteVM
{
public string Status { get; set; }
public QuoteItemVM NewQuoteItem { get; set; }
#region QuoteProperties
// Not relevant
#endregion
#region Company
// Not relevant
#endregion
#region Client
// Not relevant
#endregion
public List<QuoteItemVM> QuoteItems { get; set; }
public List<string> WorkItems = new List<string>();
public List<string> UnitList = new List<string>
{
"lm",
"fm",
"dag",
"heild",
"stk",
"klst"
};
}
In my view I've added an input field with autocomplete to add quote items when a quote item has been selected, my form posts the VM to my POST action in controller and returns the QuoteVM again with the new quote item added to the QuoteItems list, the list is ordered by quote item number property before sending it to the view. When debugging I can see that the list is being sent correctly to the view which I can also verify by writing out my QuoteItems list in a paragraph. Here I've added 4 items to my quote and everything is working as expected:
Values are still correct
Now we finally come to the problem which is that when I add an quote item that has a number lower than I have in my table it starts showing wrong values when rendering the table, but the list will be correct since the controller is returning the list correctly:
Where things start to go south...
The parts of my view that are related:
#{ // display values to check if they're correct
foreach (var item in Model.QuoteItems)
{
<p>#item.Number - #item.Description - #item.Unit</p>
}
}
<tbody>
#{ // the goal is to display them correctly here
for (int i = 0; i < Model.QuoteItems.Count(); i++)
{
<tr>
<td><input type="checkbox" class="i-checks" name="input[]"></td>
<td><input asp-for="QuoteItems[i].Number" class="form-control text-center input-sm" /></td>
<td><input asp-for="QuoteItems[i].Description" placeholder="Verkþáttur" class="form-control input-sm" /></td>
<td><input asp-for="QuoteItems[i].Quantity" placeholder="Magn" class="form-control text-center input-sm jsQuantity calculate" /></td>
<td><input asp-for="QuoteItems[i].Unit" placeholder="Eining" class="form-control text-center units input-sm" /></td>
<td><input asp-for="QuoteItems[i].UnitPrice" placeholder="Einingarverð" class="form-control text-center input-sm jsUnitPrice calculate" /></td>
<td><input asp-for="QuoteItems[i].TotalPrice" class="form-control text-center input-sm jsTotalPrice" /></td>
<td><input asp-for="QuoteItems[i].TotalPriceVAT" class="form-control text-center input-sm jsTotalPriceVAT" /></td>
</tr>
}
}
</tbody>
Has anyone run into similar problems or knows what might be causing this?
My solution was to add ModelState.Clear() before model to view.

Save Form data in database

I am trying to get the selected radio button value to from html to server side so that i can save them in the data base i have done similar in php not sure how to do that in asp.net/ C#
<form runat="server" id='attendence_form' >
<table id="attendence_div" width="100%" align="center" cellpadding="2" cellspacing="2" border="0">
<tr align="left" style="background-color:#004080;color:White;">
<td>Student Name</td>
<td>Present</td>
<td>Absent</td>
<td>Leave</td>
</tr>
<tr>
<td>ANITHA S</td>
<td><input type="radio" name="Present0" value="Present"></td>
<td><input type="radio" name="Present0" value="Absent"></td>
<td><input type="radio" name="Present0" value="Leave"></td>
</tr>
<tr>
<td>ANITHA T C</td>
<td><input type="radio" name="Present1" value="Present"></td>
<td><input type="radio" name="Present1" value="Absent"></td>
<td><input type="radio" name="Present1" value="Leave"></td>
</tr>
<tr>
<td>BINDU K V</td>
<td><input type="radio" name="Present2" value="Present"></td>
<td><input type="radio" name="Present2" value="Absent"></td>
<td><input type="radio" name="Present2" value="Leave"></td>
</tr>
</table>
Hear is the php code this recives the html form values form the user side via ajax and insert i want the same in asp.net
$conn = new mysqli($servername, $username, $password, $dbname);
// ** insert data in to data base ** //
$sql = "INSERT INTO attendance_master (AttendanceDate) VALUES ";
// **hear the data or is calculated using student as a string the number of student names are passed the same number of data is inserted in to data base ** //
foreach($_GET['student'] as $i=>$student) {
// ** so the data is inserted in to data base ** //
$sql .= sprintf("%s ('%s')"
, ($i==0 ? '' : ',')
// ** data from Ajax ** //
, mysqli_real_escape_string($conn, trim($_GET['present'][$i]))
);
}
// ** on success full function ** //
if ($conn->query($sql)) {
// **can do any thing to recognise if the data is inserted if this gives the out put then the data is shorly inserted in to data base ** //
}
you can try using <asp: RadioButton id="" runat="server" > .
In the server side you can check the "Checked" property like this
if(radioBtn.Checked==true) {}
If it is a webforms project you should use
<asp:RadioButton id="someId" runat="server">
Update:
To handle when the radiobutton is clicked you need to handle the CheckedChanged event.
someId.CheckedChanged += event_CheckedChanged;
private void event_CheckedChanged(Object sender, EventArgs e)
{
... do stuff...
}

Categories

Resources