Variable value lost before Ajax call - javascript

In the following piece of code, I am trying to pass 4 values to my controller through an AJAX call. The variable "NewType" loses its value, while the other three variables do not. NewType is pulling its value from a drop down list, while the other three are from text boxes. If I debug and step through the code, the variable retains its value. If I run the code through, the value is cleared out. Looking through similar problems, it seems obvious that it has something to do with the asynchronous Ajax call. Any ideas appreciated!!!
HTML
<tbody>
<!--Row created for each pesticide listed in Pesticides db table pulled in by Owner-->
#foreach (PesticideModel p in Model)
{
// Only show rows where IsDeleted == 0 (false)
if (#p.IsDeleted == false)
{
<tr class="toggler ui-sortable-handle" onclick="GetPestDetails()">
<!--Column for Owner-->
<td class="OwnerTD" id="OwnerBox">#p.Owner</td>
<!--Column for Brand Name-->
<td class="form-group-sm"><input type="text" name="BrandName" id="BrandName" disabled style="width:100%" value="#p.BrandName" /></td>
<!--Column for Original Brand Name-->
<td class="form-group-sm" style="display:none" id="OrigBrandName">#p.BrandName</td>
<!--Column for Pesticides Id-->
<td class="form-group-sm" style="display:none" id="PestIdBox">#p.PesticidesID</td>
<!--Column for EPA Reg No-->
<td class="form-group-sm"><input type="text" name="EPARegNo" id="EPARegNoBox" disabled style="width:100%" value="#p.EPARegNo" /></td>
<!--Column for Type-->
<td class="form-group-sm">
#*<td class="form-group-sm"><input type="text" name="Type" id="TypeBox" style="width:100%" value="#p.Type" disabled /></td>*#
#Html.DropDownListFor(x => #p.Type, (SelectList)ViewBag.Types, #p.Type, new { #class = "form-group-sm", #disabled = "disabled", id = "PType", name = "PType", onchange = "SetHiddenField(); return true;" } ) </td>
<!--Column for HiddentType --hidden column-->
<td class="HiddenType" id="HiddenType" hidden>#p.Type</td>
<!--Column for Editing Buttons-->
<td class="btn-group-sm">
<button type="button" class="btn btn-primary btn-warning" id="EditPesticideButton" name="EditButton" onclick="EditPesticideAction()">Edit</button>
<button type="button" class="btn btn-primary" id="SavePesticideButton" style="display:none" onclick="SavePesticideConfirm()">Save</button>
<button type="button" class="btn btn-primary" id="DeleteButton" style="display:none" onclick="DeletePesticideConfirm()">Delete</button>
<button type="button" class="btn btn-primary" id="CancelPesticideButton" style="display:none" onclick="CancelPesticideAction()">Cancel</button>
</td>
<!--Column for IsDeleted --hidden column-->
<td class="IsDeleted" id="IsDeleted" hidden>#p.IsDeleted</td>
</tr>
} // end if statement
} #*end foreach statement*#
</tbody>
JavaScript
var SavePesticide = function () {
var NewActiveIngredientName; //saves new textbox ActiveIngredient field
var NewEPARegNo;
var NewType;
var PesticideID;
// SaveButton click events
$("#PesticideTable").on("click", '#SavePesticideButton', function (event) {
// variables to set Name, Owner, and Id values
NewType = $(event.currentTarget).closest('tr').find('.PType').text();
NewActiveIngredientName = $(event.target).closest('tr').find('#ActiveIngredient').val();
NewEPARegNo = $(event.target).closest('tr').find('#EPARegNoBox').val();
PesticideID = $(event.currentTarget).closest('tr').find('.PesticideId').text();
// Make sure values are not empty or null
if ((NewActiveIngredientName != "" && NewActiveIngredientName != null) && (NewEPARegNo != "" && NewEPARegNo != null)) {
// send values to UpdatePestices function in controller, then to update database with new values
$.ajax({
type: "POST",
url: '#Url.Action("UpdatePesticides")',
datatype: 'json',
contentType: "application/json",
data: JSON.stringify({PType: NewType, PesticideID: PesticideID, ActiveIngredient: NewActiveIngredientName, EPARegNo: NewEPARegNo}),
success: function (data) {
alert(data);
// on success: disable all textbox fields
$("#PesticideTable").find("input[type=text]").prop("disabled", true);
$(event.target).closest('tr').find("input[type=text]").prop("disabled", true);
// on success: show edit button AND hide save, cancel, and delete buttons
$(event.target).closest('tr').find('#EditButton').show();
$(event.target).closest('tr').find('#SavePesticideButton').hide();
$(event.target).closest('tr').find('#CancelBrandButton').hide();
$(event.target).closest('tr').find('#DeleteButton').hide();
// enable edit buttons
$(".btn-warning").prop("disabled", false);
// refresh values
GetPesticideBrands();
}
});
} else {
// refresh values
GetPesticideBrands();
alert("Active Ingredient and EPA Number must contain a value")
}
})
}
Controller
public string UpdatePesticides(string Owner, string PestType, string OrigBrandName, string BrandName, string EPARegNo)
{
try
{
ADOHelper helper = new ADOHelper();
helper.UpdatePesticides(Owner, OrigBrandName, BrandName, EPARegNo, PestType);
return "Updated Successfully";
}
catch (Exception e)
{
AgRSys.Classes.Utility.Elmah_Helper.RaiseException(e);
return null;
}
}

Related

Adding Dynamic row in table, but it is emptying data in the row

What am I doing wrong here. Need help.
When I click on "Add" button, the data I selected in the rows of table are becoming blank. But When I select Delete button and then click on Add button, then it not emptying of one time only. If I see console, I can see data there, but it is not showing up on the screen.
Here is my code:
html:
<div class="container">
<div class="row" style="margin-bottom: 10px;">
<div class="col">
<div class="row111">
<label for="Select Image" class="col-sm-311 col-form-label111">Add Threshold and Notification for this Inspection: </label>
<div class="col-sm-9">
</div>
</div>
</div>
<div class="col">
<div class="float-right">
<button class="btn btn-default" type="button" (click)="addNotification()">Add</button>
</div>
</div>
</div>
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>#</th>
<th>Threshold</th>
<th>Notification Level</th>
<th>Message</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<!-- <tr> -->
<tr *ngFor="let notification of notificationArray; let i = index">
<td>{{i+1}}</td>
<td>
<select class="form-control" maxlength="50" readonly
required
id="threshold"
name="notification.thresholdId"
[(ngModel)]="notification.thresholdId"
#threshold="ngModel" >
<option value="0" selected> Select </option>
<option *ngFor="let threshold of thresholdList" value="{{threshold.thresholdId}}" >
{{threshold.threshold}}
</option>
</select>
</td>
<td>
<input [(ngModel)]="notification.notificationLevel" required class="form-control" type="text" name="notification.notificationLevel" />
</td>
<td>
<input [(ngModel)]="notification.message" required class="form-control" type="text" name="notification.message" />
</td>
<td>
<button class="btn btn-default" type="button" (click)="deleteNotification(i)">Delete</button>
</td>
</tr>
</tbody>
</table>
</div>
component.ts:
notificationArray: Array<NotificationLevel> = [];
newNotification: any = {};
ngOnInit(): void {
this.newNotification = {thresholdId: "0", notificationLevel: "", message: ""};
this.notificationArray.push(this.newNotification);
}
addNotification(index) {
this.newNotification = {thresholdId: "0", notificationLevel: "", message: ""};
this.notificationArray.push(this.newNotification);
console.log(this.notificationArray); // I can see all entered data in console
return true;
}
deleteNotification(index) {
if(this.notificationArray.length ==1) {
alert("At least one Notification Required for an Inspection");
return false;
} else {
this.notificationArray.splice(index, 1);
return true;
}
}
Ok, solve the problem:-
The main problem is in name="" attribute. name="" must differ in each row .We can solve it in two ways:
1) Either Change the name="" attributes name dynamically so that for every row it has a different name, i did it to add index number with it as
<input [(ngModel)]="notification.notificationLevel" name="notificationThreshold{{i}}" required class="form-control" type="text" />
2) Or avoid name="" and so We can avoid [(ngModel)] By [value] and (input) and can use as like :-
<input [value]="notification.notificationLevel" (input)="notification.notificationLevel=$event.target.value" required class="form-control" type="text"/>
In fact, all of your notificationArray elements is the same instance of newNotification. By doing this : this.newNotification = {thresholdId: "0", notificationLevel: "", message: ""}; you actually reset the first line too because of it.
Try to store newNotification in a var instead :
notificationArray: Array<NotificationLevel> = [];
newNotification: any = {};
ngOnInit(): void {
var newNotification = {thresholdId: "0", notificationLevel: "", message: ""};
this.notificationArray.push(newNotification);
}
addNotification(index) {
console.log(this.notificationArray);
// here is the correction
var newNotification = {thresholdId: "0", notificationLevel: "", message: ""};
this.notificationArray.push(newNotification);
console.log(this.notificationArray);
return true;
}
deleteNotification(index) {
if(this.notificationArray.length ==1) {
alert("At least one Notification Required for an Inspection");
return false;
} else {
this.notificationArray.splice(index, 1);
return true;
}
}
update :
I don't know if it's related but you'll have duplicate threshold id on your select. Use your i to make it unique.
It's the same for your input names. You should add [] after the field name otherwise only the last row will be submit.
I added a console.log of you array after the push. Can you tell in comment if the first index is reset at this point ?
Of course the row is cleared because you are clearing it:
this.newNotification = {thresholdId: "0", notificationLevel: "", message: ""};
So on clicking the add button, the bound values are overridden and then you are pushing it into the array. Thus they are cleared :)

assign value to selected input box in a row using Angular js

row add using angular code. Input box model name is "code". when click this input box a model open and when any row select using angularjs then there is a problem when I assign value using $scope.code it will assign to all input box in but I want to assign that value by which ng-click performed.
<table class="table table-bordered table-hover table-condensed">
<tr style="font-weight: bold">
<td style="width:35%">Code</td>
</tr>
<tr ng-repeat="user in users">
<td>
<!-- editable username (text with validation) -->
<span ng-show="editDel">
#{{ user.name || 'empty' }}
</span>
#{{code}}
<input type="text" name="" ng-model="code" ng-show="saveCancel" ng-click="getCode()">
</td>
<td style="white-space: nowrap">
<!-- form -->
<form ng-show="saveCancel" class="form-buttons form-inline">
<button type="submit" class="btn btn-primary">
save
</button>
<button type="button" ng-click="isCancel()" class="btn btn-default">
cancel
</button>
</form>
<div class="buttons" ng-show="editDel">
<button class="btn btn-primary" ng-click="editUser($index)">edit</button>
<button class="btn btn-danger" ng-click="removeUser($index)">del</button>
</div>
</td>
</tr>
</table>
$scope.users = [];
$scope.saveCancel = false;
$scope.editDel = true;
$scope.saveUser = function(data, id) {
//$scope.user not updated yet
angular.extend(data, {id: id});
return $http.post('/saveUser', data);
};
// remove user
$scope.removeUser = function(index) {
$scope.users.splice(index, 1);
};
// add user add row
$scope.addUser = function() {
$scope.inserted = {
id: $scope.users.length+1,
name: '',
status: null,
group: null
};
// $scope.taxNamePopup();
$scope.users.push($scope.inserted);
};
$scope.getCode = function(){
// alert(input_id);
this.code = 'nameValue';//**this assin value to selected box**
// jQuery("#tax_modal").modal("hide");
var request = $http({
method: "get",
url: base_url+"/load-tax",
data: {
},
}).then(function successCallback(response) {
jQuery("#tax_list").modal("show");
$scope.tax_data1 = response;
}, function errorCallback(response) {
});
}
$scope.getSelected = function(id,code,desc,rate){
alert(code);
this.code = code;//**but i want to assign value to selected input box from here**
jQuery("#tax_list").modal("hide");
}
$scope.safeApply(function() {
$scope.editUser = function($id){
this.saveCancel = true;
this.editDel = false;
}
});
$scope.isCancel = function(){
this.saveCancel = false;
this.editDel = true;
}
it is because ng-model is codefor every input.
Change it with following code example
<input type="text" name="" ng-model="code_$index" ng-show="saveCancel" ng-click="getCode($index)">
Now above code will change the ng-model unique for each input field and retrieve the value in getCode on the basis of index.
the model should be different for each ng-repeat item
EDIT change from getCode(user.code) to getCode(user)
<input type="text" name="" ng-model="user.code" ng-show="saveCancel" ng-click="getCode(user)">
use the param how ever you want ;)
$scope.getCode = function(user){
angular.forEach($scope.users, function (value, key) {
if (value.id == user.id) {
$scope.users[key]=user;
}
});
}

Using ajax to check radiobutton by Id in ASP.Net MVC

I saw a code that checks the radio button by value, but how do I do this by id? My current scenario is that I'm populating a table by appending html codes using ajax. I'm looping the prices of a certain item while building the html table. After that, I need to check the radio button of a price where default flag is equal to 'Y'.
Here's my if statement that checks the radiobutton by value only, this is not working yet as my radiobutton values are null, only the id and name has value:
if (item.defaultflag == 'Y')
$('#divItemPrice').find(':radio[name=rbDefaultPrice][value="iPrice_' + item.channelid + '"]').prop('checked', true);
else
$('#divItemPrice').find(':radio[name=rbDefaultPrice][value="iPrice_' + item.channelid + '"]').prop('checked', false);
Complete code:
$.ajax({
url: '/Item/RetrievePrice',
type: 'POST',
dataType: 'json',
data: JSON.stringify(json),
contentType: 'application/json; charset=utf-8',
cache: false,
async: true,
success: function (data) {
var trHTML = "";
debugger;
trHTML = '<tbody id="dbBody2">';
$.each(data, function (i, item) {
trHTML += '<tr><td class="hidden">' + item.itemid + '</td>' +
'<td style="width:20px"><label><input type="radio" name="rbDefaultPrice" id = "iPrice_' + item.itemid + '" /></label></td>' +
'<td>' + item.itemprice + '</td>' +
'<td>' + ToJavaScriptDate(item.startdate) + '</td>' +
'<td>' + ToJavaScriptDate(item.enddate) + '</td>' +
'</tr>';
//How do I check the radiobutton by id?
if (item.defaultflag == 'Y')
$('#divItemPrice').find(':radio[name=rbDefaultPrice][value="iPrice_' + item.itemid + '"]').prop('checked', true);
else
$('#divItemPrice').find(':radio[name=rbDefaultPrice][value="iPrice_' + item.itemid + '"]').prop('checked', false);
});
trHTML += '</tbody>';
$("#tblItemPrice tbody").remove();
$('#tblItemPrice').append(trHTML);
},
error: function (xhr, ajaxOptions, thrownError) {
alert("Error! " + xhr.status);
}
});
View (modal part)
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Modal Header</h4>
</div>
<div class="modal-body">
<div id="divItemPrice" class="" style="border: 0px solid green; ">
<table id="tblItemPrice" onclick="gettabledata('tblItemPrice', '0,2,3,4', 'itemPriceId,itemPrice,strtDt,endDt')" class="table table-hover table-bordered table-striped bootgrid-table" aria-busy="false" padding-left:10px;">
<thead>
<tr class="inner-table-head">
<th class="hidden">
#Html.DisplayNameFor(model => model.itemPriceId)
</th>
<th>
Price
</th>
<th>
Start Date
</th>
<th>
End Date
</th>
</tr>
</thead>
<tbody id="bodyToAppend">
</tbody>
</table>
</div>
<div class="form-group">
<div class="row form-row">
<span class="form-item">
#Html.HiddenFor(m => m.itemPriceId)
#Html.LabelFor(m => m.itemPrice, new { #class = "lbl-width" })
#Html.TextBoxFor(m => m.itemPrice, new { #class = "form-control input-sm" })
</span>
</div>
<div class="row form-row">
<span class="form-item ">
#Html.LabelFor(m => m.strtDt, new { #class = "lbl-width" })
#Html.TextBoxFor(m => m.strtDt, new { #class = "form-control input-sm", #Value = "" })
</span>
</div>
<div class="row form-row">
<span class="form-item ">
#Html.LabelFor(m => m.endDt, new { #class = "lbl-width" })
#Html.TextBoxFor(m => m.endDt, new { #class = "form-control input-sm", #Value = "" })
</span>
</div>
<div class="row form-row maintenance-btn">
<div class="btn-group">
<input type="submit" id="btnSavePrice" value="Save" class="btn btn-theme btn-sm" formmethod="post" />
<input type="submit" id="btnUpdatePrice" value="Update" class="btn btn-theme btn-sm" formmethod="post" style="display:none" />
#*<input type="submit" id="btnCancelPrice" value="Cancel" class="btn btn-theme btn-sm" />*#
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button id="closeModal" type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
The code in your if/else block cannot work because its attempting to .find() and element in the DOM which does not even exist yet (you have not added it). And even if you did add the <tr> to the DOM in each iteration it would result in poor performance (searching the whole table in each iteration).
A simple way to solve this (and much easier to debug the html your generating) is to create a hidden template that is cloned and added in each iteration. I also assume that you want to add the value of itemprice as the value attribute of the radio button so that you can get the value of the selected radio button using var price = $('input[name="rbDefaultPrice"]').val();
<table id="template" style="display:none;">
<tr>
<td>
<label>
<input type="radio" name="rbDefaultPrice" class="radio" />
<span class="price"></span>
</label>
</td>
<td class="startdate"></td>
<td class="enddate"></td>
</tr>
</table>
Then in the .each() loop, clone the template, update its values and append it to the DOM
var tbody = $('#tblItemPrice tbody');
....
success: function (data) {
tbody.empty() // remove existing rows
$.each(data, function (i, item) {
// clone the template row
var row = $('#template').clone().find('tr');
// update properties
var radio = row.find('.radio');
radio.val(item.itemprice);
if (item.defaultflag == 'Y') {
radio.prop('checked', true);
}
row.find('.price').text(item.itemprice);
row.find('.startdate').text(....
// add the row to the DOM
tbody.append(row);
});
}
Side note: Its not clear what your ToJavaScriptDate() function is doing, but I suggest you just pass the correctly formatted value to client so you can just use row.find('.startdate').text(item.startdate); etc

Focus lost on Pop-up dialog when browse for File uisng AngularJS pop-up modal

AngularJS boostrap pop-up modal code:
<div class="modal-header">
<h3 class="modal-title">Add Gallery</h3>
</div>
<div class="modal-body">
<input type="file" id="file1" name="file" class="filestyle" onchange="angular.element(this).scope().AddPhotoGallery(this.files)" data-buttonname="btn-primary" />
<span ng-bind="fileValidationMessage" style="color: red;"></span>
<div ng-show="showFileData || isUpdate">
<table id="fileTable" class="table table-striped">
<thead>
<tr>
<td ng-if="!isUpdate">File Name</td>
<td>Image</td>
<td>Message</td>
<td>Action</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="obj in fileObjectList">
<td ng-if="!isUpdate">{{obj.fileName}}</td>
<td><img ng-src="{{obj.fileImageUrl}}" alt="No Profile Picture shows" height="150" width="150" class="img-rounded img-responsive" /></td>
<td>{{obj.fileMessage}}</td>
<td><input type="button" value="Remove" class="btn btn-primary" ng-click="deletePhoto(obj.id)" /></td>
</tr>
</tbody>
</table>
<div class="form-group">
<input type="button" class="btn1 btn-sm" ng-click="UploadFiles()" value="Upload Gallery" ng-show="isAddImage" />
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-warning" type="button" ng-click="close()">
Cancel
</button>
</div>
$scope.AddPhotoGallery = function ($files) {
$scope.isAddImage = true;
$scope.galleryValidationMessage = '';
var isValid = false;
// Update scenerio $scope.images.length > 0
if ($scope.images.length > 0 && $scope.images.length < 2) {
$scope.images.length++;
angular.forEach($scope.images, function (value, key) {
$scope.fileObjectList.push({
'id': $scope.fileCnt,
'fileMessage': 'File Added to Gallery',
'fileName': value.name,
'fileData': value
})
$scope.fileCnt++;
$scope.isUpdate = true;
});
}
else if ($scope.fileCnt < 2 && $scope.images.length == 0) {
angular.forEach($files, function (value, key) {
isValid = $scope.doFileValidation(value.name);
if (isValid) {
$scope.fileObjectList.push({ 'id': $scope.fileCnt, 'fileName': value.name, 'fileData': value,
'fileMessage': 'File Added to Gallery '
})
$scope.fileCnt++;
}
});
} else {
$scope.fileValidationMessage = "Cannot add more pictures. ";
}
if ($scope.fileCnt > 0) {
$scope.showFileData = true;
}
};
Issue:
When I click on browse for adding file the pop-up controller 'AddPhotoGallery' function call and push the data in fileObjectList. Table/Div is bind to 'showFileData' and it is true when fileCnt > 0 (as see in last line of 'AddPhotoGallery' function). The issue is table/div and the data inside it shows only when I click ANYWHERE on the pop-up screen. It seems that focus shifted to last action i.e. file browse dialog and it didn't come back to the pop-up dialog.
More Explanation:
if ($scope.fileCnt > 0) {
$scope.showFileData = true;
}
When the $scope.showFileData is true the div/table and the data inside it should show immediately but it is showing when I click ANYWHERE on the modal pop-up. I know the actual cause and that is focus doesn't come back to modal pop-up after browse.
Can anywhere suggest how to get the control/focus back to pop-up modal on after file added using File Browse?

Knockoutjs foreach with if inside table

I have a foreach creating a table in one of my pages. My goal is when they checked the checkbox I would show additional elements for that table
My issue is when the table is first drawn everything works as expected. But if i check a checkbox after the table is drawn the ko if statement does not reevaluate. What is the best method to accomplish this goal? My current code is below.
<tbody data-bind="foreach: AvailableCerts">
<tr>
<td>
<label class="label-checkbox inline">
<input type="checkbox" data-bind="value: Id, checked: IsSelected">
<span class="custom-checkbox"></span>
<span data-bind="text:Name"></span>
</label>
</td>
<td data-bind="text:CertifyingBody"></td>
<td>
<!-- ko if: (IsSelected) -->
<input data-bind="value : EntryDate" required type="date" class="form-control input-sm">
<!-- /ko -->
</td>
<td>
<!-- ko if: ExitDateRequired -->
<input data-bind="value : ExitDate" required type="date" class="form-control input-sm">
<!-- /ko -->
</td>
<td>
<!-- ko if: CaseNumberRequired -->
<input data-bind="value : CaseNumber" required type="text" class="form-control input-sm">
<!-- /ko -->
</td>
</tr>
</tbody>
And my viewModel
function AppViewModel() {
var self = this;
self.rootUrl = window.location.protocol + "//" + window.location.host + "/Certs/";
self.AvailableCerts = ko.observableArray([]);
self.getAvailableCerts = function () {
$.ajax({
url: self.rootUrl + "AvailableCerts",
type: "GET",
cache: false,
dataType: "json",
success: function (results) {
if (results != null) {
self.AvailableCerts(results);
} else {
self.AvailableCerts([]);
}
}
});
};
self.getAvailableCerts();
}
ko.applyBindings(new AppViewModel());
The contents of the ko.observableArray AvailableCerts are not observable by default. If you plan on working with the data after downloading it, you need to make the data for each of the certs observable as well. So, something like this in your Ajax call:
self.getAvailableCerts = function () {
$.ajax({
url: self.rootUrl + "AvailableCerts",
type: "GET",
cache: false,
dataType: "json",
success: function (results) {
if (results != null) {
for (var i = 0; i < results.length; i++) {
self.AvailableCerts().push({
'IsSelected': ko.observable(results[i].IsSelected),
'ExitDateRequired': ko.observable(results[i].ExitDateRequired),
'CaseNumberRequired': ko.observable(results[i].CaseNumberRequired)
});
}
} else {
self.AvailableCerts([]);
}
}
});
};
Or checkout the mappings plugin.

Categories