How to realod bootstrap table after post via ajax - javascript

I'm using bootstrap table to display a rows from a database, it's MVC ASP.NET and I've put my data in a ViewBag and returned that View with viewbag included as a data to display, so it looks like this:
<div class="row rpad">
<div class="col-md-12">
<div class="z-panel-2">
<div class="oneRow">
<table id="cT">
<thead>
<tr>
<th>
Name
</th>
<th>
Date & time
</th>
<th>
Type
</th>
<th>
Homework done
</th>
<th>
Teacher
</th>
</tr>
</thead>
<tbody>
#foreach (var item in ViewBag.AllClasses)
{
<tr class="class" id="#item.ID">
<td>#item.Date</td>
<td>#item.Type.Name - #item.User_Class.ClassType.NumberOfLessons</td>
<td>
#if (item.HomeWorkDone ?? false)
{
<i class="fa fa-check" aria-hidden="true"></i>
}
</td>
<td>
#item.User.Name
</td>
</tr>
}
</tbody>
</table>
As it's possible to notice I'm looping all data ViewBag.AllClasses and I'm displaying a data as a rows in a table..
When users clicks on a row I'm updating a database with values : homework is readen : true
$.ajax({
url: '#Url.Action("setHomework", "homework")',
type: "GET",
data: { id: id },
And next time user reloads a page, this condition will be executed (as mentioned in a code above):
#if (item.HomeWorkDone ?? false)
{
i class="fa fa-check" aria-hidden="true"></i>
}
Code above means if user has value of true on a homework field, fontawesome icon will be displayed so he will know that he red that homework, but I'm wondering how can I realod content of this bootstrap table after he clicked on that row, so he do not need to reload page to see that mark (font awesome icon) on that row.. ( as a sign that homework is red)
I hope there is another way instead of refreshing whole page/view..
Thanks

I think you can add a success callback to your ajax call. Inside that.. you could append a td to that row.
$.ajax({
url: '#Url.Action("setHomework", "homework")',
type: "GET",
data: { id: id },
success: function (data) {
if (data == "1") { // worked as it should
$(row).find('td:last').after('<td><i class="fa fa-check" aria-hidden="true"></i></td>');
}
}
});
I think a cleaner way will be to have a td there by default and just change the class of icon depending on item.HomeWorkDone. So it would be something like:
$(row).find('.fa-exclamation-circle').addClass('fa-check').removeClass('fa-exclamation-circle');
Also, it is recommended to use HTTP POST for update operations.

Related

I'm trying to auto populate labels(with parameters from object) on selecting option from dropdown list

I'm new to mvc and html/js both.
So the basic idea of what I am trying to do is:
Dropdown(used to select bookTitle)
Labels below get auto populated with selected book details from dropdown(id,title,author,price,quantity,etc)
Button on the side of these labels which will add this obj into a List
Whole list will then be used for checkout
I'm stuck with the auto-populated labels and add button
Would be a grateful if anyone would be willing to help me
Here is my code:
'''
#model IEnumerable<BookWebApp.Models.Books>
#{
ViewData["Title"] = "OrderBooks";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<html>
<center>
<h1>OrderBooks</h1>
<hr/>
<div id="Title">
<select id="Title_Select">
<option value="" selected-disabled>
Book Names
</option>
#foreach(var item in Model)
{
<option value=#item.Title>
#item.Title
</option>
}
</select>
</div>
<button onclick="getValue()"> Check Details</button>
<hr/>
<div>
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.BookID)
</th>
<th>
#Html.DisplayNameFor(model => model.Title)
</th>
<th>
#Html.DisplayNameFor(model => model.Author)
</th>
<th>
#Html.DisplayNameFor(model => model.Price)
</th>
<th>
#Html.DisplayNameFor(model => model.Quantity)
</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
//labels for obj here
</tr>
</tbody>
</table>
</div>
</center>
'''
To populate the list you can do as you did with the DropdownList with a foreach and insert all the fields in the order of the header and on the last one check with value id.
Finally, a push button for the with an onclick function.
In the onclick function you scroll through the list and take Id of all the checkboxes that have the checked property.
You now have the list of all the selected books.
if you want I can give you an example but I suggest you see for yourself that it is much more instructive, tell me if you want the example
There are two ways you can add the labels to the list and then bring the list to the Checkout page, use ajax to post data or use MVC submission. I would recommend the first one (using ajax) because the page will not be refreshed.
Solution 1: Use ajax
Create a Controller method to save the record
Whenever the user click on the button, make an ajax call to post the item to the method, save it to somewhere (Persistence database or cache)
When user navigate to the check-out page, retrieve the list and display to the user
Also you may want to add a remove button for easily manage.
Here's the code to populate the labels:
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.BookID)
</th>
<th>
#Html.DisplayNameFor(model => model.Title)
</th>
<th>
#Html.DisplayNameFor(model => model.Author)
</th>
<th>
#Html.DisplayNameFor(model => model.Price)
</th>
<th>
#Html.DisplayNameFor(model => model.Quantity)
</th>
<th>
<!-- This one is for the add button -->
</th>
</tr>
</thead>
<tbody>
#foreach(var label in Model.Labels)
{
<tr class="table-row">
// labels for obj here
<td class="label-id">#label.Id</td>
<td class="label-id">#label.Title</td>
<td class="label-id">#label.Author</td>
<td class="label-id">#label.Price</td>
<td class="label-id">#label.Quantity</td>
<td>
<button class="btn-add-to-collection" onclick="addLabel(this)"></button>
</td>
</tr>
}
</tbody>
<script>
function addLabel(el) {
// query for the properties value then use ajax to post the data to controller
// also save it to the current page state for easily modify
}
</script>
There are multiple methods to achieve your goal to auto populate label data:
Set Attribute values to your select which comprise of details of books.
1.1. Implement an onChange function for your select which will populate data from Select attribute in your labels.
Implement an onChange function for your select which will send an ajax call to your controller.
2.1. Retrieve values from controller and populate relevant values in labels
Create a separate button, on its onClick send an ajax call to your controller.
3.1. Retrieve values from controller and populate relevant values in labels
Now coming to Adding data in list:
Why providing separate buttons for all labels?
Why not add a button Proceed to check out?
And for that you can do:
$.each($(table).find('tbody tr'), function (j, row) {
});
in this code you get all your label values and push them in the list proceed as you please
I hope this helped, if you need code snippets for above mentioned processes, let me know, I will update my answer accordingly.
Edit 1, Solution 1
<div>
<center>
<h1>OrderBooks</h1>
<hr />
<div id="Title">
<select id="Title_Select" onchange="SelectOnChange()">
<option value="" selected-disabled>
Book Names
</option>
#foreach (var item in Model)
{
<option value=#item.BookID>
#item.Title
</option>
}
</select>
</div>
<hr />
<div>
<table class="table" id="BooksTable">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.BookID)
</th>
<th>
#Html.DisplayNameFor(model => model.Title)
</th>
<th>
#Html.DisplayNameFor(model => model.Author)
</th>
<th>
#Html.DisplayNameFor(model => model.Price)
</th>
<th>
#Html.DisplayNameFor(model => model.Quantity)
</th>
<th></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<hr />
<button onclick="ProceedCheckOut()"> Proceed to CheckOut</button>
</div>
</center>
</div>
$(document).ready(function () {
SelectOnChange = function () {
var BookId = $("#Title_Select :selected").val();
var URL = '/Underwriting/Case/GetBookDetailsById';
var _data = {
BookId: BookId
};
$.ajax({
url: URL,
type: "POST",
dataType: "html",
contentType: "application/json",
data: JSON.stringify(_data),
async: true,
success: function (result) {
var Books = JSON.parse(result);
var tr = '<tr>' +
'<td id="BookID">' + Books.BookID + '</td>' +
'<td id="Title">' + Books.Title + '</td>' +
'<td id="Author">' + Books.Author + '</td>' +
'<td id="Price">' + Books.Price + '</td>' +
'<td id="Quantity">' + Books.Quantity + '</td>' +
'</tr>';
$('#BooksTable > tbody').append(tr);
},
error: function (jqXHR, textStatus, errorThrown) {
$Extention.HideLoader();
_$.Notification("YOU MIGHT BE ENTERING WRONG VALUES.", 200);
}
});
}
ProceedCheckOut = function () {
var Books = new Object()
$('#BooksTable tbody tr').each(function (i, field) {
Books.BookID = parseInt($(field).find('#BookID').text());
Books.Title = $(field).find('#Title').text();
Books.Author = $(field).find('#Author').text();
Books.Price = parseFloat($(field).find('#Price').text());
Books.Quantity = parseInt($(field).find('#Quantity').text());
});
console.log(Books);
}
});
I have made minor changes to your code:
Implemented an onChange button, removed GetDetails button, In OnChange button i have called my controller function to get details from database against BookId.
Once i get book details from controller i render that data in my Ajax success
Created a Proceed to checkout button, this button gets data from table and inserts it in an object, now you can use that object to send book data to another page or your controller.
In case of further help please let me know

Laravel 7 - Update value of checkbox without form or button

I'm stuck with my project, please help...
This is the situation: In my project I have to assign a teacher to give permission to grade students, because a group can have 2 or more teachers, but only one has to have permission to grade, so... I added a column in my table 'teachers' in the database with the name 'grade' of type boolean. And in my view I added a checkbox... How do I change the value of a checkbox without using any form or button to trigger the action and activate the checkbox in the teacher who is going to have permission to grade? And this value should also be updated in the database.
This is my view...
<!--teachers-->
<table class=" table table-sm table-striped table-bordered ">
<thead class="text-white bg-primary">
<tr>
<th>#lang('show.Identifier')</th>
<th>#lang('show.email')</th>
<th>#lang('show.grade')</th>
<th>#lang('show.delete')</th>
</tr>
</thead>
<tbody class="small text-center">
#foreach ($group->teachers as $teacher)
<tr>
<td >{{$teacher->Identifier}} </td>
<td >{{$teacher->email}} </td>
<td>
<input id="active" {{$teacher->grade == 1 ?'checked':''}} type="checkbox" name="grade" value="1">
</td>
<td>
<form method="post" action="{{url('Groups/Disenroll/'.$group->idGroup.'?idTeacher='.$teacher->idTeacher)}}">
{{csrf_field()}}
<button type="submit" class="btn btn-sm btn-outline-danger" > <i class="material-icons small" >call_split</i></button>
</form>
</td>
</tr>
#endforeach
</tbody>
</table>
And this is an image of the table, if it helps...
I think you can use something like JQuery for this.
You can firstly add a class of toggle-class to your checkbox
<input class="active toggle-class" {{$teacher->grade == 1 ?'checked':''}} type="checkbox" name="grade">
And secondly, make sure that you have a way to keep track of who's doing the grades.
Add data-id="{{ $teacher->Identifier}}" on your checkbox
<input data-id="{{ $teacher->Identifier}}" class="active toggle-class" {{$teacher->grade == 1 ?'checked':''}} type="checkbox" name="grade">
In your web.php add a new route
Route::get('/path/to/updateGrader/status', [App\Http\Controllers\MyController::class, 'updateGraderStatus']);
Add the below code to where your checkbox is located
$('.toggle-class').on('change',function(){
let status = $(this).prop('checked') == true ? true : false;
let grader_id = $(this).data('id');
$.ajax({
type:'GET',
dataType:'json',
url:'/path/to/updateGrader/status', // add your earlier created route here
data:{'grade': status, 'grader_id': grader_id},
success: function(data){
console.log('success');
}
});
});
In your Controller, MyController in our case create a new function
public function updateGraderStatus(Request $request)
{
$grader = MyModel::find($request->grader_id);
$grader->grade = $request->grade;
$grader->save();
}
Please let me know if this helps you. I didn't test it out but I think this is how you would go about it.

Deleting the row of HTML table using tr.remove(), submit button is sending back only rows above it and not below it

I have a HTML table for which i have delete button for each row.
Clicking on the delete button, it goes to javascript and I remove the row using below code . When I try to submit the table content back to the controller using the submit (Ajax.beginform), it is sending back the data only above the deleted row, and nothing below the deleted row. Even though in the UI, it is still showing all the rows above and below the deleted row.
Example: Lets say if I upload 3 documents, and delete the middle one, it will remove the row from the table but when I click on the Upload button, I get only the first row.
But if I delete the last row, 3rd document, then I am getting back above 2 documents properly in my Upload button action.
Thanks in advance for your help
javascript code:
function removeDocument(selector) {
$(selector).closest('tr').remove();
}
HTML code:
#using (Ajax.BeginForm("Upload", "MatterFiling", new AjaxOptions { HttpMethod = "POST", OnSuccess = "SuccessUploadDocument", OnFailure = "OnUploadFailure" }))
{
<table class="table table-bordered" id="DocumentTable">
<thead>
<tr>
<th><span class="reqAsterisk">* </span>Document Title</th>
<th></th>
</tr>
</thead>
<tbody>
#for (int i = 0; i < Model.Count(); i++)
{
<tr>
<td style="width: 50%; display:none" class="nr" >
#Html.TextAreaFor(m => Model.FileName, htmlAttributes: new { #class = "form-control dmm-autoresize", #rows = "1" })
</td>
<td>
<a style="color:red; cursor:pointer" onclick="removeDocument(this)">
<i class="far fa-trash-alt"></i>
</a>
</td>
</tr>
}
</tbody>
</table>
<input type="submit" name="UploadButton" value="Upload" id="UploadDocsButton" class="btn btn-primary"/>
}
This is after deleting the row
This is before deleting the row
if you are using form then you have refresh your form, you can also try to name the input types name with array like username[].

Laravel duplicated view after selecting dropdown option

I have a problem with my Laravel view. I am getting the desired data through ajax and I can also show that data in my view. However, I found that whenever I select something in my dropdown then the data appears, but the overall layout gets duplicated. I see my console and find that inside the table I have another layout created after selecting something with the dropdown. I have my code here please take a review of it.
<select>`enter code here`
#foreach(App\StudentsClass::all() as $class)
<option id="class{{$class->id}}" value="{{$class->id}}">{{$class->class_name}}</option>
#endforeach
</select>
<table id="studentsData" class="table table-striped table-bordered table-list-search">
<thead>
<tr>
<th>#</th>
<th>Student ID</th>
<th>Student Name</th>
<th>Attendance</th>
</tr>
</thead>
#foreach($students as $student)
<tbody>
<tr>
<th>{{$student->id}}</th>
<td>{{$student->student_id}}</td>
<td>{{$student->first_name}} {{$student->last_name}}</td>
<td>
<div class="form-group">
<select class="form-control" id="gender">
<option>Present</option>
<option>Absent</option>
<option>Leave</option>
</select>
</div>
</td>
</tr>
</tbody>
#endforeach
</table>
<a class="fas fa-folder-open btn btn-success float-right mb-4 mr-2"> Save</a>
</div>
<script>
$(document).ready(function () {
#foreach(App\StudentsClass::all() as $class)
$("#class{{$class->id}}").click(function () {
var classes = $("#class{{$class->id}}").val();
$.ajax({
url: '{{url('/students/attendance')}}',
type: "GET",
dataType: "html",
data: 'class_id=' + classes,
success:function(response) {
// console.log(response);
$('table[id=studentsData]').html(response);
}
});
});
#endforeach
});
Its hard to say without knowing exactly that is returned by the ajax call -- but it sounds like you may be returning the either a full view (Everything from <html> to </html>) and inserting it into the table ... or the full html markup for a table, creating new nested tables on each ajax call.
Can you share the result of your ajax call? (What you see with console.log(response); )
Also, I don't think this is related but noticed a few things you could do to your code to simplify. For example, Id suggest changing your dropdown's structure a bit and giving it an ID like so ...
<select id="class_select">
#foreach(App\StudentsClass::all() as $class)
<option value="{{$class->id}}">{{$class->class_name}}</option>
#endforeach
</select>
And then rather than looping through each class and adding dedicated function, you could adjust your javascript to find the class ID and trigger the ajax call each time the dropdown is changed.
<script>
$(document).ready(function(){
$('#class_select').change(function(){
var class = $(this).val();
$.ajax({
url: '{{url('/students/attendance')}}',
type: "GET",
dataType: "html",
data: 'class_id=' + classes,
success:function(response) {
// console.log(response);
$('#studentsData').html(response);
}
});
});
});
</script>
Hope that helps! If we could see what the ajax call returns I think we could give a better answer.

Display confirmation message next to a single table row

Trying to show "Product Added!" message to the right of the row where the user selected 'Add'. The way I have it right now is:
var addToCart = function (idFromButton) {
$.ajax({
type: "POST",
data: { prodID: idFromButton },
url: '#Url.Action("Add", "ShoppingCart")',
success: function (data)
{
$('#BadgeIcon').html(data).fadeOut(1).fadeIn('fast');
$('.fakeLink-' + idFromButton).text("Product Added!").css("color", "green").fadeIn(600).fadeOut("slow");
}
});
}
which changes the 'Add' button green and fades it away.
I have also tried creating a new row element to the right of the 'Add' column and adding the message there. It works, but moves the 'Add' button to the left during the fading animation, not to mention that it permanently removes the border of that last column upon click until page is refreshed.
Here is my table:
<table class="table" id="table">
<tr>
<th>
Product Name
</th>
<th>
Price
</th>
<th>
Image
</th>
<th>
Add to Cart
</th>
</tr>
#if (Model.Results.Any())
{
foreach (var item in Model.Results)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#item.Price.ToString("$0.00")
</td>
<td>
#if (item.ImageFile != null)
{
<img src="#Url.Content(item.ImageFile)" />
}
</td>
<td>
<input id="fakeLink" class="fakeLink-#item.ProductID" type="submit" value="Add" onclick="addToCart(#item.ProductID)" />
</td>
</tr>
}
}
else
{
<tr>
<td colspan="4">No product found.</td>
</tr>
}
</table>
Any help would be greatly appreciated.
Your code looks fine except you need to update the button's value, not text. You may use the val() method.
$('.fakeLink-' + idFromButton).val("Product Added!")
.css("color", "green").fadeIn(600).fadeOut("slow");
Also, i see you have duplicate id values for your button's inside the loop. Your id's should be unique. Actually you do not really need an Id for this case. You can simplify your code with unobutrusive javascript like this
<td>
<input class="addBtn" data-product="#item.ProductID" type="submit" value="Add" />
</td>
and listen to the click event of this type of button (button with addBtn css class) and you can use $(this) as the reference of clicked button.
$(function() {
$(".addBtn").click(function(e) {
e.preventDefault();
var _this = $(this);
$.ajax({
type: "POST",
data: { prodID: _this.data("product") },
url: '#Url.Action("Add", "ShoppingCart")',
success: function (data) {
_this.val("Product Added!").css("color", "green").fadeIn(600)
.fadeOut("slow");
}
});
});
});
EDIT : If you want to keep the Add button intact, but want to show a message next to that, you can do this.
success: function (data) {
var msg = $("<span />").html("Product added").css("display","none");
msg.appendTo(_this.parent()).fadeIn(500).fadeOut("slow");
}
You may apply additional css styles to the message span as needed.

Categories