jQuery's appendTo method causes "context is undefined" error - javascript

A page has two drop-downs which should be populated from a JSON array. When the array is processed it contains the option elements which need to be appended to the drop-downs. This task is granted to the jQuery's appendTo method which, however, causes an error to appear:
"TypeError: context is undefined".
Do you know why this is happening and how to fix it?
The source code is available below, as well on jsFiddle.
HTML:
<select id="ddlTypeNew">
<option value="">Select Type To Add</option>
</select>
<select id="ddlTypeEdit">
<option value="">Select Type To Edit</option>
</select>
JavaScript:
var json = $.parseJSON('[{ "MailTypeId": 1, "MailTypeName": "Register" }, { "MailTypeId": 2, "MailTypeName": "Login" }]');
json = json.map(function (obj) {
return $('<option>', { value: obj.MailTypeId, text: obj.MailTypeName });
});
$(json).slice().appendTo('#ddlTypeEdit');
$(json).appendTo($('#ddlTypeNew'));

You can do it like this:
var json = $.parseJSON('[{ "MailTypeId": 1, "MailTypeName": "Register" }, { "MailTypeId": 2, "MailTypeName": "Login" }]');
$.each(json,function (index,obj) {
$($('<option/>').val(obj["MailTypeId"]).html(obj["MailTypeName"])).appendTo('#ddlTypeEdit');
$($('<option/>').val(obj["MailTypeId"]).html(obj["MailTypeName"])).appendTo('#ddlTypeNew');
});

Map here actually returns a array of jQuery option objects. You need to loop through the array and then add them one by one to the dropdown like this:
var json = $.parseJSON('[{ "MailTypeId": 1, "MailTypeName": "Register" }, { "MailTypeId": 2, "MailTypeName": "Login" }]');
var arr = json.map(function (obj) {
return $('<option>', { value: obj.MailTypeId, text: obj.MailTypeName });
});
$.each(arr, function(i, n){
n.appendTo('#ddlTypeEdit');
})
OR JUST:-
$('#ddlTypeEdit').append(arr);

Related

Facing Issue in ajax

I am new to laravel and ajax... i want to show the state of the selected country in dropdown list but when i select the country from the dropdown list it get data from the laravel perfectly and get it in ajax also.. but it is not able to append the data in html option tag.. for more details i am attaching the code of ajax also...`
$("#country").change(function(e){
var countryid = $(this).val();
console.log("Change Event Happpened on id : "+ countryid);
$.ajax({
type :"GET",
url :"GetStates/"+countryid,
success : function(statelist){
$("#state").empty();
$("#state").append('<option> Select State...</option>')
$.each(statelist,function (statename,stateid) {
**$("#state").append('<option>' + statename + ' </option>') // This line of code is not working**
console.log("in each function");
});
}
});
})
`
You're using jQuery.each function wrongly. jQuery.each callback function accepts two arguments:
Function( Integer indexInArray, Object value )
So according to your (wrong) code:
$.each(statelist,function (statename,stateid)
statename holds index of item and stateid receives statelist item, which clearly is against your idea.
Assuming that statelist has the following structure:
statelist = [
{
statename: 'LA',
stateid: 1
}
]
callback function should look like the following:
$.each(statelist,function (index, state) {
$("#state").append(`<option value="${state.stateid}">${state.statename}</option>`)
});
You can use javascript object destructuring to make this simpler:
$.each(statelist,function (index, {stateid, statename}) {
$("#state").append(`<option value="${stateid}">${statename}</option>`)
});
Working code:
const statelist = [{
statename: "LA",
stateid: 1
},
{
statename: "MA",
stateid: 2
},
];
$("#state").empty();
$("#state").append("<option value=''>Please select a state...</option>");
$.each(statelist, (index, {
statename,
stateid
}) => {
$("#state").append(`<option value="${stateid}">${statename}</option>`);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<select id="state">
<option>This will be removed</option>
</select>

How Can I Populate Dropdown Select Element using getJSON

I want to populate dropdown select menu.
i need to get bankName and iINNo from this JSON
My JSON :
{"status":true,"message":"Request Completed","data":[{"id":1,"activeFlag":1,"bankName":"Union Bank of India","details":"Union Bank of India","iINNo":"607161","remarks":"","timestamp":"21/11/2016 16:00:00"},{"id":2,"activeFlag":1,"bankName":"Bank of India","details":"Bank of India","iINNo":"508505","remarks":"","timestamp":"21/11/2016 16:00:00"},],"statusCode":0}
My Javacript :
let dropdown = $('#Bank');
dropdown.empty();
dropdown.append('<option selected="true" disabled>Select Bank</option>');
dropdown.prop('selectedIndex', 0);
const url = 'http://cors-anywhere.herokuapp.com/';
// Populate dropdown with list of provinces
$.getJSON(url, function (data) {
$.each(data, function (res, code) {
console.info(res);
console.info(code);
dropdown.append($('<option></option>').attr('value', value.iINNo).text(index.bankName));
})
});
The array with bank data is under the property data inside the JSON. So the trick is to loop over that property - right now you loop over the entire JSON response, including the status and message properties.
You will get the individual bank object as the second argument item and then you can access it's properties and append it to your dropdown:
$.each(data.data, function (index, item) {
console.info('Bank Data: ', item);
dropdown.append($('<option></option>').text(item.bankName));
});
This should work
const banks = document.getElementById('banks');
banks.innerHTML = '<option selected="true" disabled>Select Bank</option>';
fetch('https://cors-anywhere.herokuapp.com/http://www.allindiaapi.com/HMESEVAAEPS/GetBankDetails?tokenkey=KzhnBIUi1wuM97yizKJ07WB3YwPSykyX9CjB6C6O5LRyClZ9YZl9NcIk5f6Fjna4')
.then(response => response.json())
.then(response => {
if(response.status){
response.data.forEach(bank => {
const option = document.createElement('option');
option.value = bank.iINNo;
option.innerContent = bank.bankName;
});
}
});
<select id="banks"></select>
The issue is because the data you need is in the data property of the data object, so you need to loop over data.data. In addition the properties of each object will be in the second argument of the handler function, code in your example. For example code.bankName.
However it's worth noting that the code can be tidied, and also have its performance improved by using map() to build a single string of option elements which you append to the DOM only once. Try this:
let $dropdown = $('#Bank');
$dropdown.html('<option value="" disabled>Select Bank</option>').val('');
// AJAX commented for example only:
//$.getJSON(url, function(data) {
let data = {
"status": true,
"message": "Request Completed",
"data": [{
"id": 1,
"activeFlag": 1,
"bankName": "Union Bank of India",
"details": "Union Bank of India",
"iINNo": "607161",
"remarks": "",
"timestamp": "21/11/2016 16:00:00"
}, {
"id": 2,
"activeFlag": 1,
"bankName": "Bank of India",
"details": "Bank of India",
"iINNo": "508505",
"remarks": "",
"timestamp": "21/11/2016 16:00:00"
}, ],
"statusCode": 0
}
let html = data.data.map(bank => `<option value="${bank.iINNo}">${bank.bankName}</option>`);
$dropdown.append(html);
//});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<select id="Bank"></select>

Checkboxes to be checked after saving in angularjs

I am using angularjs for my application.I am using multiple checkbox selection and storing it in database in the format [1,2,3,4,5].For example if the checkbox selected is 1 then i am storing the value as 1.If multiple are selected then 1,2,3, and so on.
Here is the html
<div class="col-xs-12">
<div data-ng-repeat="healthStatus in HealthStatuses">
<input id="chkCustomer_{{healthStatus.Value}}" value="
{{healthStatus.Value}}" type="checkbox"
data-ng-checked="selection.indexOf(healthStatus.Value) > -1"
data-ng-click="toggleSelectionHealthStatus(healthStatus.Value)" />
{{healthStatus.Name}}</label>
</div>
</div>
Here is the controller.js
$scope.HealthStatuses = [{
Name: 'Alzheimers',
Value: 1,
Selected: false
}, {
Name: 'Arthritis',
Value: 2,
Selected: false
},{
Name: 'Cancer',
Value: 3,
Selected: false
},{
Name: 'Cellulitis',
Value: 4,
Selected: false
}];
Here is how i am pushing the selected checkboxes value
$scope.selectionHealthStatus=[];
$scope.toggleSelectionHealthStatus = function toggleSelection(Value) {
var idx = $scope.selectionHealthStatus.indexOf(Value);
if (idx > -1) {
$scope.selectionHealthStatus.splice(idx, 1);
} else {
$scope.selectionHealthStatus.push(Value);
}
};
Now while retrieving the data i want the checkboxes to be checked.But now it is not happening.
Here is how i am retrieving the data
userPageService.getHealthStatus().then((data) => {
data = data.data;
$scope.formData = data;
});
If i put console for $scope.formData this is what i get.
participantIllnessAndDisability:"[1, 2, 3, 4]"
Here participantIllnessAndDisability is one field with multiple checkboxes selected.Now what i want to do is after adding the data while viewing i want the selected checkboxes to be checked.I am getting the data from database in [1,2,3] format.The datatype for field participantIllnessAndDisability in database is String.
At load of page, the function on ng-checked won’t get automatically called. Hence it won’t check the check box.
You could assign ng-model or ng expression to checked property and initialize it from controller on data load.
Update:
Please try this.
userPageService.getHealthStatus().then((data) => {
data = data.data;
$scope.formData = data;
$scope.HealthStatuses.forEach((o) => o.Selected = JSON.parse(data.participantIllnessAndDisability).includes(o.Value));
});

How to get Select2 to update a ajax call when country value is changed

I can't seem to find an easy example of how to update the states list when the country list has changed. All examples I've seen to be using all sorts of bits and peices that work depending on version and who is giving the solution.
Can someone help me how this can be easily done without ugly hacks. I've tried this so far and whilst it works, if I change the drop down for the second time, the new values just get appended to the old ones instead of replacing them. I've tried destroying and rebuilding but old values remain.
The data coming back from the server is valid json with id and text values. So far I've had no luck in getting the state list to update with new country state values when the country is changed
<select id="country" name="country" class="form-control" data-placeholder="Select...">
<optgroup label="Country">
<option></option>
<option value="US" > United States</option>
<option value="AU" > Austrailia</option>
</optgroup>
</select>
<select id="state" name="state" class="form-control" data-placeholder="Select...">
<optgroup label="State">
<option></option>
</optgroup>
</select>
$("#country").select2().on("change", function(e) {
var country = e.val;
$.post("states", {
country_id: country
}, function(e) {
if (e)
$("#states").select2({
data: e
});
})
});
$("#state").select2();
These are the values sent back from server
[{ id: 'ALB', text: 'ALABAMA' }, { id: 'ALS', text: 'ALASKA' }, { id: 'ARI', text: 'ARIZONA' }]
You have to remove the <option> tags from the select before setting the new data:
$.post("states", {
country_id: country
}, function(e) {
if (e){
$("#states option").remove();
$("#states").select2({
data: e
});
}
})
You may want to refine my example to avoid removing placeholders, if any.
See also this JSFiddle: https://jsfiddle.net/drj84go5/
The best option is to have an input (text) not a select2 and then convert it through select2 function using ajax.
Input:
<input type="text" id="states">
Javascript:
$('#states').select2({
placeholder: "States...", // placeholder
allowClear: true,
minimumInputLength: 0,
dropdownCssClass: "bigdrop",
width: '100%',
ajax: {
quietMillis: 2500,
url: "/Search/_SearchStates", // Server-side action
dataType: 'json',
data: function (term, page) {
return {
Text: term, // Text to search for
CountryId: $("#country").val(), // CountryId from #countries
};
},
results: function (data, page) {
return { results: data };
},
},
formatResult: function (item) {
return item.StateName; // Table name/description
},
id: function (element) {
return element.StateId; // Table id/code
},
formatSelection: function (item) {
return item.StateName; // Table name/description
}
});
You need to have a server-side action that will give you the list of states.
To get the StateId you need to do:
$("#states").select2('val');

knockout.js - nested array data and cascading pre-populated dropdown lists binding

I'm fairly new to knockout.js, however, I've been happily using it in my ASP.NET MVC 4 project, until I ran into this obstacle which has been bothering me for a while, can't seem to put my finger on it.
The scenario which I'm working on requires several combinations of location data (region, country, city), i.e. cascading dropdown lists, which isn't a problem to do when inputting fresh data, but I ran into problem(s) when trying to edit the saved data.
Data is in JSON format, with nested arrays, looks like this (shortened for illustration purposes):
var newData =
[
{
"ID":1,
"Name":"Australia and New Zealand",
"Countries":[
{
"ID":13,
"Name":"Australia",
"Cities":[
{
"ID":19,
"Name":"Brisbane"
},
{
"ID":28,
"Name":"Cairns"
},
...
I suspect I can't load the data (or more clearly, to bind it) properly since I'm having trouble accessing the Region sub-array (which contains Region's Countries) and the Countries sub-array (which contains Countries' Cities).
Then there's the matter of having prepopulated options, which works partially, the viewmodel loads the number of lines, but doesn't select anything.
Here's the VM:
var existingRows = [
{
"Region": 1,
"Country": 13,
"City": 19
},
{
"Region": 1,
"Country": 158,
"City": 3
}];
var Location = function (region, country, city) {
var self = this;
self.region = ko.observable(region);
self.country = ko.observable(country);
self.city = ko.observable(city);
// Whenever the region changes, reset the country selection
self.region.subscribe(function () {
self.country(undefined);
});
// Whenever the country changes, reset the city selection
self.country.subscribe(function () {
self.city(undefined);
});
};
var LocationViewModel = function (data) {
var self = this;
self.lines = ko.observableArray(ko.utils.arrayMap(data, function (row)
{
var rowRegion = ko.utils.arrayFirst(newData, function (region)
{
return region.ID == row.Region;
});
var rowCountry = ko.utils.arrayFirst(rowRegion.Countries, function (country) {
return country.ID == row.Country;
});
var rowCity = ko.utils.arrayFirst(rowCountry.Cities, function (city) {
return city.ID == row.City;
});
return new Location(rowRegion, rowCountry, rowCity);
}));
// Operations
self.addLine = function () {
self.lines.push(new Location())
};
self.removeLine = function (line) {
self.lines.remove(line)
};
};
var lvm = new LocationViewModel(existingRows);
$(function () {
ko.applyBindings(lvm);
});
HTML code:
<tbody data-bind="foreach: lines">
<tr>
<td><select data-bind="options: newData, optionsText: 'Name', optionsValue: 'ID', optionsCaption: 'Select a region...', attr: { name: 'SubRegionIndex' + '['+$index()+']' }, value: region"></select></td>
<td><select data-bind="options: Countries, optionsText: 'Name', optionsValue: 'ID', optionsCaption: 'Select a country...', attr: { name: 'CountryIndex' + '['+$index()+']' }, value: country"></select></td>
<td><select data-bind="options: Cities, optionsText: 'Name', optionsValue: 'ID', optionsCaption: 'Select a city...', attr: { name: 'CityIndex' + '['+$index()+']' }, value: city"></select></td>
<td><a href='#' data-bind='click: $parent.removeLine'>Remove</a></td>
</tr>
</tbody>
I tried to modify the Cart editor example from the knockout.js website with prepopulated data, but haven't really made much progress, I seem to be missing something. Didn't really find anything with nested arrays so I'm stuck here...
I've put up the full code on JSFiddle here:
http://jsfiddle.net/fgXA2/1/
Any help would be appreciated.
The problem is the way in which you are binding to the selected item in your select lists:
<select data-bind="
options: newData,
optionsText: 'Name',
optionsValue: 'ID',
value: region">
</select>
Here you are binding the ID property from your JSON data to the region property on your view model.
This means that when you bind your second select list:
<td data-bind="with: region">
<select data-bind="
options: Countries,
optionsText: 'Name',
optionsValue: 'ID',
value: $parent.country">
</select>
</td>
You attempt to bind to region.Countries. However, region simply contains the selected region ID. In this case the console is your friend:
Uncaught Error: Unable to parse bindings. Message: ReferenceError:
Countries is not defined;
The same problem is true of your third select list for Cities since you are now attempting to bind to country.Cities where country is also just the ID.
There are two options available here. The first is to remove the optionsValue parameters, thus binding the actual JSON objects to your view model properties. That and a binding error on your Cities select box (you were binding to CityName instead of Name) were the only problems:
http://jsfiddle.net/benfosterdev/wHtRZ/
As you can see from the example I've used the ko.toJSON utility to output your view model's object graph. This can be very useful in resolving problems (in your case you would have seen that the region property was just an number).
The downside of the above approach is that you end up storing a copy of all of the countries, and their cities for the selected country in your view model.
A better solution if dealing with large data sets would be to only store the selected identifier (which I believe you were attempting to do originally) and then define computed properties that filter your single data set for the required values.
An example of this can be seen at http://jsfiddle.net/benfosterdev/Bbbt3, using the following computed properties:
var getById = function (items, id) {
return ko.utils.arrayFirst(items, function (item) {
return item.ID === id;
});
};
this.countries = ko.computed(function () {
var region = getById(this.selectedRegion.regions, this.selectedRegion());
return region ? ko.utils.arrayMap(region.Countries, function (item) {
return {
ID: item.ID,
Name: item.Name
};
}) : [];
}, this);
this.cities = ko.computed(function () {
var region = getById(this.selectedRegion.regions, this.selectedRegion());
if (region) {
var country = getById(region.Countries, this.selectedCountry());
if (country) {
return country.Cities;
}
}
}, this);
You can see from the rendered object graph that only the currently selected countries and cities are copied to the view model.

Categories