Delete Datatables row with media-id in button? $(this).closest("tr").remove(); won't work - datatables

I'm looking for a way to remove a row from a table, but I can't do this anymore. I used to do this by entering an id in the tag, however nowadays I fill the table with json and Ajax and do not enter an id in the tag anymore.
Now I do add an id in the last column of the buttons: data-id. Can I do something with this?
HTML:
<tr role="row" class="even">
<td class="dtr-control"><img src="../images/red_thumb/1743.jpg" class="mediabank-preview-thumbnail"></td>
<td>1743.jpg</td>
<td>Beschrijving</td>
<td>Redactie</td>
<td class="sorting_1">01-12-2021 13:26:53</td>
<td>
<button class="btn btn-primary btn-sm edit" data-id="1743">
<span class="glyphicon glyphicon-pencil"></span>
</button>
<button class="btn btn-danger btn-sm remove" data-id="1743">
<span class="glyphicon glyphicon-remove"></span>
</button>
</td>
</tr>
I try a lot with something like $(this).closest("tr").remove() But this won't work...
Jquery:
$('#table_mediaBank').on('click', '.remove', function () { // Verwijder media
var id = $(this).data('id');
var media = $(this).closest('tr').find('td:eq(1)').text();
if(confirm("Weet je zeker dat je media '" + media + "' wilt verwijderen?")) {
$.ajax({
url: 'pages/delete.php',
type: 'POST',
data: {id: id},
error: function() {
alert('Er is iets fout gegaan met het verwijderen van media-ID ' + id);
},
success: function(data) {
//alert(data);
//$("#"+id).remove(); OLD WAY to remove the row when ID is in <tr>
$(this).closest("tr").remove();
}
});
}
});
The record is removed from the mySQL database. Why $(this).closest("tr").remove(); won't work?
Can anybody help me?

This works!
$('#table_mediaBank').on('click', '.remove', function () {
var id = $(this).data('id');
var media = $(this).closest('tr').find('td:eq(1)').text();
var row = $('#table_mediaBank').DataTable().row($(this).closest('tr')); // In variable schrijven omdat het in de Ajax succes funtion niet mogelijk is om naar 'this' te verwijzen
if(confirm("Weet je zeker dat je media '" + media + "' wilt verwijderen?")) {
$.ajax({
url: 'pages/delete.php',
type: 'POST',
data: {id: id},
error: function() {
alert('Er is iets fout gegaan met het verwijderen van media-ID ' + id);
},
success: function(data) {
//alert(data);
row.remove().draw();
}
});
}
});

Related

Laravel ajax my column id is not being shown by console.log

Demonstration on how my catagory_id is being read (console.log each time I press the edit button)
$(document).on('click','.edit_category',function (e) {
e.preventDefault();
var cat_id = $(this).val();
console.log(cat_id);
});
My problem is when I try to output the an array shown at the consoles by clicking the edit button (testing purposes)
Not sure how I still get the 404 as the category_id is already defined in the table
blade:
<td>
<button type="button" value="${cat.category_id}" class="edit_category btn btn-outline-secondary"><i class="fas fa-edit"></i> Edit</button>
<button type="button" value="${cat.category_id}" class="delete_category btn btn-outline-secondary"><i class="fas fa-trash"></i> Delete</button>
</td>
ajax:
$(document).on('click','.edit_category',function (e) {
e.preventDefault();
var cat_id = $(this).val();
// console.log(cat_id);
$('#editCategoryModal').modal('show');
$.ajax({
type: "GET",
url: "/bbr-category-configuration-edit/"+cat_id,
success: function (response) {
console.log(response);
}
});
});
controller:
public function edit($category_id) {
$category_edit = HmsBbrCategory::find($category_id);
if ($category_edit)
{
return response()->json([
'status'=>200,
'status'=>$category_edit,
]);
}
else
{
return response()->json([
'status'=>404,
'status'=>'Category Not Found',
]);
}
}
model:
public $timestamps = false;
protected $table = 'hms_bbr_category';
route:
Route::get('/bbr-category-configuration', [BBRCategoryConfigurationController::class,'index']);
Route::get('/bbr-category-configuration-data', [BBRCategoryConfigurationController::class,'fetchcategory']);
Route::post('/bbr-category-configuration', [BBRCategoryConfigurationController::class,'store']);
Route::get('/bbr-category-configuration-edit/{category_id}', [BBRCategoryConfigurationController::class,'edit']);
any advice or input would be appreciated, thankyou

Form collection validation with dates and string - Vuelidate

I am trying to validate series of dates with something like this.
const data = [
{begin: new Date('2019-12-01'), place: '2'},
{begin: new Date('2019-12-03'), place: '3'}
... more values
];
// Elements inside data can be added or removed but will have at least one.
Here data[1][begin] should be more than or equal to data[0][begin] and data[1][place] should not equal to data[0][place]. Is there anyway to achieve this. Documentation talks about dynamic validation but I am not sure how I can achieve this with collection.
You can consider implementing a custom validation in the form submit event listener.
This can be achieved by looping through your array of objects and compare items in pairs.
HTML
<form
id="app"
#submit="checkForm"
action="/someurl"
method="post"
>
<table border="1">
<tr v-for="(item,index) in dates" :key="index">
<td>
{{index}}
</td>
<td>
{{formatDate(item.begin)}}
</td>
<td>
{{item.place}}
</td>
</tr>
</table>
<input type="date" v-model="dateEntry"/>
<input type="text" v-model="placeEntry"/>
<button type="button" #click="addEntry">Add</button>
<p>
<br>
<input
type="submit"
value="Submit"
>
</p>
<p v-for="error in errorList">
{{error}}
</p>
</form>
JS
new Vue({
el: "#app",
data: {
errorList: [],
dateEntry: null,
placeEntry: null,
dates: [
{begin: new Date('2019-12-01'), place: '2'},
{begin: new Date('2019-12-03'), place: '3'}
]
},
methods: {
addEntry: function(){
if(this.dateEntry == null || this.dateEntry == "")
return false;
if(this.placeEntry == "")
return false;
this.dates.push({
begin: new Date(this.dateEntry),
place: this.placeEntry
});
this.dateEntry = null;
this.placeEntry= "";
},
checkForm: function(e){
var isValid = true;
var index = 0;
var nextIndex = 1;
this.errorList = [];
while(nextIndex < this.dates.length){
if(nextIndex < this.dates.length){
var isValidDate = this.validDate(this.dates[nextIndex].begin,this.dates[index].begin);
var isValidPlace = this.validPlace(this.dates[nextIndex].place,this.dates[index].place);
if(!isValidDate){
this.errorList.push("Invalid date on index " + nextIndex);
}
if(!isValidPlace){
this.errorList.push("Invalid place on index " + nextIndex);
}
}
index++;
nextIndex++;
}
if(!this.errorList.length){
this.errorList.push("All dates are valid");
return true;
}
e.preventDefault();
},
formatDate: function(date){
return date.toDateString();
},
validPlace: function(curPlace, prevPlace){
return curPlace != prevPlace;
},
validDate: function(curDate,prevDate){
try{
return curDate.getTime() >= prevDate.getTime();
}catch(e){
return false;
}
}
}
})
Check out this JS Fiddle that I created to illustrate my suggestion.
On the other hand, if you are building the array during runtime, then you can apply the validation before it gets added into the array.

VueJS default/starting a value ina list of searched terms

Trying to make a search plugin using Vue and I'm having a problem with adding a starting/default value to the list of options. If I comment out the pair or template lines involving the start prop the rest of it works fine, but nothing renders if I leave them in.
Component Code:
Vue.component('search', {
props: {
type: String,
hidein: String,
start: {
type: Object,
default: null
}
},
//props: ['type', 'hidein', 'start'],
data: function () {
return {
search: "",
select: "",
results: [],
};
},
template: '<div #load="loaded"><input :id="hidein" type="text" v-model="search" #keyup="updateList">'+
'<input type="hidden" :name="hidein" v-model="select" class="form-control">'+
'<div v-if="start">Current: <span #click="select=start.id" :class="{\'label label-success\':(select==start.id)}>'+
'+ {{start.name}}</span></div>'+
'<div v-if="results.length">Do you mean:<ul>'+
'<li v-for="result in results" :key="result.id"><span #click="select=result.id" :class="{\'label label-success\':(select==result.id)}">'+
'+ {{result.name}}</span></li>'+
'</ul></div></div>',
methods: {
updateList: function(e) {
var response = [];
console.log("search: "+this.search);
$.ajax({
method: "GET",
url: "/api/search/"+this.type,
data: { key: this.search }
}).done(function( msg ) {
this.results = msg;
console.log(this.results);
}.bind(this));
},
loaded: function () {
this.select=!!this.start ? this.start.id : null;
}
},
});
Component Call:
<search type="ships" hidein="ship_id" ></search>
Can anyone tell me what I'm doing wrong? (Besides the hacked together template, that's hopefully a completely separate issue with the pipeline I'm having)
There is a missing " here
:class="{\'label label-success\':(select==start.id)}
But also, please, use a template literal to make your life easier.
`<div #load="loaded"><input :id="hidein" type="text" v-model="search" #keyup="updateList">
<input type="hidden" :name="hidein" v-model="select" class="form-control">
<div v-if="start">
Current:
<span #click="select=start.id" :class="{'label label-success':(select==start.id)}">
{{start.name}}
</span>
</div>
<div v-if="results.length">
Do you mean:
<ul>
<li v-for="result in results" :key="result.id">
<span #click="select=result.id" :class="{'label label-success':(select==result.id)}">
{{result.name}}
</span>
</li>
</ul>
</div>
</div>`

Watin. how to show invinsible class

HTML code:
<div class="col-sm-9">
<input name="NewCardOrAccountNumber" class="form-control ui-autocomplete-input" id="NewCardOrAccountNumber" type="text" value="" autocomplete="off">
<span class="ui-helper-hidden-accessible" role="status" aria-live="polite"></span>
</div>
<div class="unvisible" id="clientInfoNew">
<div class="form-group">
<label class="col-sm-3 control-label">FIRST NAME</label>
<div class="col-sm-9" id="FnameNew"></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">LAST NAME</label>
<div class="col-sm-9" id="LnameNew"></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">BIRTH DATE</label>
<div class="col-sm-9" id="BirthDateNew"></div>
</div>
Watin code:
[TestMethod]
[TestCategory("Rimi Change card page")]
public void Rimi_4444_Change_Card_and_Assert()
{
//Web Address
using (IE ie = new IE(this.Rimi))
{
//IE ie = new IE(RimiChangeCard);
ie.BringToFront();
ie.ShowWindow(WatiN.Core.Native.Windows.NativeMethods.WindowShowStyle.Maximize);
ie.TextField(Find.ById("NewCardOrAccountNumber")).TypeText("9440385200600000020");
If I write card number from keyboard, the invisible class appear, and you can see FIRST NAME, LAST NAME and so on. But if I do this with watin, it does not appear, and you only see card number which you input. Its like hidden fields of information. I do not know how to make that I could see this fields when I input card number.
There would be a JavaScript function, which gets executed when you manually enter the data in the text field.Go through the Java Script functions on the same page which refer to that element using it's ID NewCardOrAccountNumber.
Refer to this link for sample application. Where msg_to is element, and has a KeyUp event associated. When that filed gets a , value, there is a div section inside which a `Subject' field is shown.
Similarly, after executing the TypeText, try to trigger related event mentioned in the Java Script event using Java script execution.
EDIT: I see that the javascript functions gets executed after bulr event is fired. This means the textbox field should loose the focus. Try the below options.
// 1. Try focusing out of control.
ie.TextField(Find.ById("NewCardOrAccountNumber")).TypeText("9440385200600000020");
ie.TextField(Find.ById("OldCardOrAccountNumber")).Click();
ie.WaitForComplete();
// 2. Try Using Send Keys method to tab out.
ie.TextField(Find.ById("NewCardOrAccountNumber")).TypeText("9440385200600000020");
System.Windows.Forms.SendKeys.SnedWait("{TAB}"); // Need to add System.Windows.Forms reference to the project.
I put image on the internet, so click on this link Image and you will see on first image how look page, second picture - what have to happen when you input card number (from keyboard), third - what happen when card namuber is input from watin (does not appear information about card).
HTML code:
<div class="ibox-content">
<br>
<div class="form-horizontal">
<div class="row">
<div class="col-md-5">
<div class="form-group">
<label class="col-sm-3 control-label">NEW CARD</label>
<input name="NewCardId" id="NewCardId" type="hidden" value="0" data-val-required="The NewCardId field is required." data-val-number="The field NewCardId must be a number." data-val="true">
<div class="col-sm-9"><span class="ui-helper-hidden-accessible" role="status" aria-live="polite"></span><input name="NewCardOrAccountNumber" class="form-control ui-autocomplete-input" id="NewCardOrAccountNumber" type="text" value="" autocomplete="off"></div>
</div>
<div class="unvisible" id="clientInfoNew">
<div class="form-group">
<label class="col-sm-3 control-label">FIRST NAME</label>
I maybe find what you looking for Sham, but I do not know how to use it :
<script type="text/javascript">
$(document).ready(function() {
var NewCardId = "#NewCardId";
var OldCardId = "#OldCardId";
var NewCardNumber = "#NewCardOrAccountNumber";
var OldCardNumber = "#OldCardOrAccountNumber";
$(NewCardNumber).autocomplete(
{
source: function(request, response) {
$.ajax({
url: '/LoyaltyWebApplication/Suggestion/GetCardSuggestions',
dataType: "json",
data: {
str: $(NewCardNumber).val()
},
success: function(data) {
response($.map(data, function(item) {
var label = "";
if (item.Fname != null) label += item.Fname;
if (item.Lname != null) label += " " + item.Lname;
if (label.trim() != '') label = " (" + label.trim() + ")";
return {
value: item.CardNumber,
label: item.CardNumber + label
}
}));
},
error: function(xhr, ajaxOptions, thrownError) {
alert(xhr.status);
alert(thrownError);
}
});
},
select: function(event, ui) {
getCardDetails($(NewCardNumber), $(NewCardId), 'newCardSegments', true);
$("#newCardSegments").hide();
$("#clientInfoNew").show();
},
minLength: 2
}).blur(function() {
getCardDetails($(NewCardNumber), $(NewCardId), 'newCardSegments', true);
});
$(OldCardNumber).autocomplete(
{
source: function(request, response) {
$.ajax({
url: '/LoyaltyWebApplication/Suggestion/GetCardSuggestions',
dataType: "json",
data: {
str: $(OldCardNumber).val()
},
success: function(data) {
response($.map(data, function(item) {
var label = "";
if (item.Fname != null) label += item.Fname;
if (item.Lname != null) label += " " + item.Lname;
if (label.trim() != '') label = " (" + label.trim() + ")";
return {
value: item.CardNumber,
label: item.CardNumber + label
}
}));
},
error: function(xhr, ajaxOptions, thrownError) {
alert(xhr.status);
alert(thrownError);
}
});
},
select: function(event, ui) {
getCardDetails($(OldCardNumber), $(OldCardId), 'oldCardSegments', false);
$("#oldCardSegments").hide();
},
minLength: 2
}).blur(function() {
getCardDetails($(OldCardNumber), $(OldCardId), 'oldCardSegments', false);
});
function getCardDetails(cardNumHolder, cardIdHolder, segmentTablePlace, isNew) {
$.getJSON('/LoyaltyWebApplication/LOV/SetId?lovType=ReplacementLOV&lovValue=' + cardNumHolder.val(), null,
function(data) {
$("#clientInfo" + ((isNew) ? "New" : "Old")).show();
if (cardNumHolder.val() == '') {
return;
}
var i;
for (i = 0; i < data.otherNames.length; i++) {
$("#" + data.otherValues[i] + (isNew ? "New" : "Old")).text(data.otherNames[i]);
}
cardIdHolder.val(data.Id);
$.getJSON('/LoyaltyWebApplication/Replacement/ClientSegmentsList?clientId=' + data.Id + "&no_cache=" + Math.random, function(data) {
$("#" + segmentTablePlace).find('tbody').empty();
if (data.length > 0) {
$.each(data, function(index) {
$("#" + segmentTablePlace).find('tbody').append("<tr><td>" + data[index].SegmentCode + "</td><td>" + data[index].SegmentName + "</td></tr>");
});
$("#" + segmentTablePlace).show();
}
});
});
}
$("#resetVal").click(function() {
$("#NewCardOrAccountNumber").attr("value", "");
$("#NewCardOrAccountNumber").val("");
$("#NewCardId").attr("value", "");
$("#NewCardId").val("");
$("#clientInfoNew").hide();
$("#OldCardOrAccountNumber").attr("value", "");
$("#OldCardOrAccountNumber").val("");
$("#OldCardId").attr("value", "");
$("#OldCardId").val("");
$("#clientInfoOld").hide();
return false;
});
});
</script>

Knockout JS -> Update the view with value from new GET Call

I am consuming web services. I am making GET call to get all the questions -> user will answer that question and post it using the post call. This part is working as expected right now. Now, I would like make another GET call as soon as POST call is successful. I am able to make a GET call after POST call is complete but view is still showing data from my old GET call. How can I update the view with information from new GET call.
GET -> POST -> New GET (Data is not updated in this call.)
JSON
{
"Respondent_ID":"hello111",
"Group_Name":"",
"Product_ID":80,
"Language_ID":1,
"First_Name":"hello",
"Last_Name":"111",
"Respondent_EMail":"",
"Gender":"M",
"AllQuestions":[
{
"Question_Number":76,
"Question_Text":"I think ",
"Definition":"",
"Answer":0
},
{
"Question_Number":77,
"Question_Text":"I am ",
"Definition":"",
"Answer":0
},
{
"Question_Number":78,
"Question_Text":"I am mild mannered",
"Definition":"",
"Answer":0
},
{
"Question_Number":79,
"Question_Text":"I am strong",
"Definition":"",
"Answer":0
},
{
"Question_Number":80,
"Question_Text":"I am a risk taker",
"Definition":"",
"Answer":0
}
],
"AnswerChoice":[
{
"Answer_Choice":"Strongly disagree",
"Answer_Choice_Value":1
},
{
"Answer_Choice":"Disagree",
"Answer_Choice_Value":2
},
{
"Answer_Choice":"Neutral",
"Answer_Choice_Value":3
},
{
"Answer_Choice":"Agree",
"Answer_Choice_Value":4
},
{
"Answer_Choice":"Strongly agree",
"Answer_Choice_Value":5
}
]
}
--
#{
ViewBag.Title = "Questions";
}
<html>
<body>
<script src="~/Scripts/knockout.mapping-latest.js"></script>
<script>
function GetAllEmployees() {
$.ajax({
url: '/api/Questions?respondent_id=hello111',
type: 'GET',
dataType: 'json',
success: function (data) {
var data2 = data.AllQuestions;
var viewModel = {
data: ko.mapping.fromJS(data2),
Question_Number: ko.observable(data.AllQuestions[0].Question_Number),
Question_Text: ko.observable(data.AllQuestions[0].Question_Text),
save: function () {
$.ajax({
url: '/api/lms',
type: 'POST',
data: data,
dataType: 'json',
success: function (data) {
$.ajax({
url: '/api/Questions?respondent_id=hello111',
type: 'GET',
dataType: 'json',
success: function (data) {
//How can update the view with the new data I got from the get call.
}
ko.applyBindings(viewModel);
}
});
},
error: function (x, y, z) {
alert(x + '\n' + y + '\n' + z);
}
});
}
}
ko.applyBindings(viewModel);
},
error: function (x, y, z) {
alert(x + '\n' + y + '\n' + z);
}
});
}
</script>
</body>
</html>
Get Questions
<form data-bind="submit: save">
<table>
<thead>
<tr><th>#</th>Question<th>Strongly disagree</th><th>Strongly disagree</th><th>Disagree</th><th>Neutral</th><th>Agree</th><th>Strongly agree</th></tr>
</thead>
<tbody data-bind="foreach: $data">
<tr>
<td>
<span data-bind="text: Question_Number"></span>
</td>
<td>
<span data-bind="text: Question_Text"></span>
</td>
<td><input type="radio" class="radio" value="1" data-bind="attr: { name: Question_Number}"></td>
<td><input type="radio" class="radio" value="2" data-bind="attr: { name: Question_Number }"></td>
<td><input type="radio" class="radio" value="3" data-bind="attr: { name: Question_Number }"></td>
<td><input type="radio" class="radio" value="4" data-bind="attr: { name: Question_Number }"></td>
<td><input type="radio" class="radio" value="5" data-bind="attr: { name: Question_Number }"></td>
</tr>
</tbody>
</table>
<button type="submit">Go</button>
</form>
You must un-nest your code.
And you should start to use jQuery's native .get() and .post() calls and deferred callbacks (.then(), .done(), .fail(), .always()) for Ajax handling.
I rewrote your JS code:
function showAjaxError(x, y, z) {
alert(x + '\n' + y + '\n' + z);
}
function QuestionViewModel(respondentId) {
var self = this;
self.data = ko.observableArray();
self.currentQuestionId = ko.observable();
self.currentQuestion = ko.computed(function () {
return self.data()[self.currentQuestionId()];
});
self.mapQuestions = function (rawData) {
return ko.mapping.fromJS(rawData.AllQuestions);
};
self.rewind = function () {
self.currentQuestionId(0);
};
self.updateFromServer = function () {
$.get('/api/Questions', { respondent_id: respondentId })
.then(self.mapQuestions)
.done(self.data)
.done(self.rewind)
.fail(showAjaxError);
};
self.save = function () {
$.post('/api/lms', { data: ko.mapping.toJS(self.data) })
.done(self.updateFromServer)
.fail(showAjaxError);
};
self.updateFromServer();
}
ko.applyBindings(new QuestionViewModel('hello111'));
Notes
'/api/Questions?respondent_id=hello111' should not be hard-coded. Make it a variable.
View models work best when they are built with a constructor, because otherwise it's very hard to make them refer to themselves internally.
Don't repeat yourself. Make small, re-usable functions (like showAjaxError()) and re-use them. If your code nests more than 3 levels deep you are doing it wrong.
By commonly accepted coding style conventions, everything that is not a constructor starts with a lowercase letter and names don't have underscores (i.g. questionText instead of Question_Text).