Facing Issue in ajax - javascript

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>

Related

AJAX Receive multiple data

I am trying to populate some drop down fields. I have the following dropdown:
Continent
Country
Sport
I want to select first Continent, after that the Country and Sport to populate dynamically. Example:
Europe -> (All Europe countries appear correctly, they are in db).
I choose Algeria; the Sport names should appear on drop down. The json is correct but the ajax, I know, is wrong!
Here is my code:
$(document).ready(function(){
$('#select_continents').on('change', function(){ //continent drop down ID
$('#select_countries').empty();// country drop down ID
$('#select_sport').empty();// sport drop down ID
$.ajax({
method: 'GET',
url: './json.php',
data: { json_continent_country : 1, continent : $('#select_continents').val(), json_country_sport : 1, country : $('#select_countries').val() }
})
.done(function(data){
$.each(JSON.parse(data), function(i, val)
{
$('#select_countries').append('<option value="'+val.id+'">'+val.country_name+'</option>');
$('#select_sport').append('<option value="'+val.id+'">'+val.sport_name+'</option>');
})
})
.fail(function(){
alert('error');
})
})
})
This is what I get:
Any advice?
Why are you reloading the sports list only in case the continent is changed? You are saying that you wish to update the sports list when the country changes, that's not what your code is doing.
Try this instead (omitting any formatting or text elements):
<script type="text/javascript">
$('#continent').on('change', function() {
var continent= $('#continent').val();
// update sport list
$.ajax('./json.php', {
data: {
"continent": continent
}, success: function(data) {
// clear and update sports SELECT
$('#country').html('');
for (var i in data) {
$('#country').append($('<option>').val(data[i].val_id).text(data[i].country_name)
}
}
});
});
$('#country').on('change', function() {
var continent= $('#continent').val();
var country= $('#country').val();
// update sport list
$.ajax('./json.php', {
data: {
"continent": continent, // most likely not relevant, country itself should suffice
"country": country
}, success: function(data) {
// clear and update sports SELECT
$('#sport').html('');
for (var i in data) {
$('#sport').append($('<option>').val(data[i].val_id).text(data[i].sport_name)
}
}
});
});
</script>
<body>
<select id="continent">
<option value="Europe">Europe</option>
</select>
<select id="country">
</select>
<select id="sport">
</select>
</body>
besides, your val.id in your code is the same for country and sport?

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

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);

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');

Item selection MVC view with KnockoutJS

I am trying to implement a generic ASP.net MVC view. The UI should display a list of available and selected items loading data (basically list of string) from server. User can make changes into the list i.e. can select new items from available item list and also can remove items from selected list.
I wanted to do it using KnockoutJS as to take advantage of binding.
I manage to complete it upto the point everything is working except showing selected item as checked when the view is initialized in available list. E.g. As Shown Here
I tried various options (using template (closest to what I want to achieve), Checked attr, possible options), the issue is if I manage to display item checked some other functionality breaks. Tried defining a template but could not get it to work in my case.
HTML:
<div class='moverBoxOuter'>
<div id='contactsList'>
<span data-bind="visible: availableItems().length > 0">Available countries: </span>
<ul data-bind="foreach: availableItems, visible: availableItems().length > 0">
<li>
<input type="checkbox" data-bind="checkedValue: $data, checked: $root.selectedItems" />
<span data-bind="text: title"></span>
</li>
</ul>
<span data-bind="visible: selectedItems().length > 0">Selected countries: </span>
<ul data-bind="foreach: selectedItems, visible: selectedItems().length > 0">
<li>
<span data-bind="text: title"></span>
Delete
</li>
</ul>
</div>
JS:
var initialData = [
{
availableItems: [
{ title: "US", isSelected: true },
{ title: "Canada", isSelected: false },
{ title: "India", isSelected: false }]
},
{
selectedItems: [
{ "title": "US" },
{ "title": "Canada" }
]
}
];
function Item(titleText, isSelected) {
this.title = ko.observable(titleText);
this.isSelected = ko.observable(isSelected);
}
var SelectableItemViewModel = function (items) {
// Data
var self = this;
self.availableItems = ko.observableArray(ko.utils.arrayMap(items[0].availableItems, function (item) {
return new Item(item.title, item.isSelected);
}));
self.selectedItems = ko.observableArray(ko.utils.arrayMap(items[1].selectedItems, function (item) {
return new Item(item.title, item.isSelected);
}));
// Operations
self.selectItem = function (item) {
self.selectedItems.push(item);
item.isSelected(!item.isSelected());
};
self.removeItem = function (removedItem) {
self.selectedItems.remove(removedItem);
$.each(self.availableItems, function (item) {
if (item.title === removedItem.title) {
item.isSelected = false;
}
});
};
}
var vm = new SelectableItemViewModel(initialData);
$(document).ready(function () {
ko.applyBindings(vm);
});
Could you please help, see jsfiddle below:
http://jsfiddle.net/sbirthare/KR4a6/6/
**Update: Follow up question below **
Its followup question:
I need to add a combobox on same UI e.g. for US state. The available items are counties, based on user selection in state combo I need to filter out counties. I am getting data from server using AJAX and its all successful BUT the displayed list is not refreshing. I was expecting having binding setup correctly, if we change the observable array in viewmodel, the UI should change. I tried forcing change to availableItems but it just display all items. Please see if you can spot the problem in below code where I am updating ViewModel observable array.
function multiselect_change() {
console.log("event: openmultiselect_change");
var selectedState = $("#stateDropdownSelect").val();
var propertyName = $("#PropertyName").val();
var searchId = #Model.SearchId;
var items;
var model = { propertyName: propertyName, searchId: searchId, stateName: selectedState };
$.ajax({
url: '#Url.Action("GetFilterValues", "Search")',
contentType: 'application/json; charset=utf-8',
type: 'POST',
dataType: 'html',
data: JSON.stringify(model)
})
.success(function(result) {
debugger;
items = JSON.parse(result);
vm.availableItems(items.AvailableItems);
//vm.availableItems.valueHasMutated();
//var item = document.getElementById('availableItemId');
//ko.cleanNode(item);
//ko.applyBindings(vm, item);
vm.filter(selectedState);
})
.error(function(xhr, status) {
alert(status);
});
}
As user3426870 mentioned, you need to change the value you passed to the checked binding to boolean.
<input type="checkbox" data-bind="checkedValue: $data, checked: isSelected" />
Also, I don't think you need to have selectedItems in the initial data.
Instead in the viewModel, you can do something like:
self.selectedItems = ko.computed(function() {
return ko.utils.arrayFilter(self.availableItems(), function (item) {
return item.isSelected();
});
});
It's because you give an array to the binding checked while it's supposed to be a value comparable to true or false (like undefind or an empty string).
I would use a function checking if the $data is in your array and returning a boolean to your binding.
Something like that!

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