replacing select box dynamically inside of a div - javascript

I want replace the select box inside of the div
<div class="models">
<select disabled="disable">
<option>Model Name</option>
</select>
</div>
I'm trying to target the div and load the select box like this
jQuery('.models select').change(function() {
var model = jQuery('.models option:selected').text();
I'm not getting any action on change though
http://jsfiddle.net/HNgKt/

Simple change: bind your change event handler to the container div (which should be present when this executes) and get the text value from that:
jQuery('.models').on('change','select',function() {
var model = jQuery(':selected',this).text();
var modelValue = jQuery(':selected',this).val();
});
Note: your fiddle and markup has it diabled, of course it would need to be enabled first, something like:
jQuery('.models>select').prop('disabled',false);
EDIT: Using your fiddle, I mashed around, commented out your load - as it does not work there and the cleanstring, not present, and this works:
jQuery('.brands').change(function () {
alert('here');
var brand = jQuery('.brands option:selected').text();
// brand = cleanString(brand);
//jQuery('.models').load('/pf-models #' + brand);
jQuery('.models>select').append('<option >She is a classic</option>').prop('disabled', false);
});
alert(jQuery('.models>select').prop('disabled'));
jQuery('.models').on('change', 'select', function () {
var model = jQuery(":selected", this).text();
alert(model);
model = cleanString(model);
jQuery('#show-models').load('/pf-urls #' + model);
});
updated fiddle: http://jsfiddle.net/HNgKt/6/
EDIT Further detailed example, still based on the valid markup assumptions coming back from the load on the first part which I have substituted for a html replace since we have not access to that part:
jQuery('.brands').change(function () {
var brand = jQuery('.brands option:selected').text();
$('.models').html('<select class="models"><option >' + brand + ' She is a classic</option><option>clunker</option></select>');
});
jQuery('.models').on('change', 'select', function () {
var model = jQuery(":selected", this).text();
alert('model:' + model);
});
Fiddle for that: http://jsfiddle.net/HNgKt/7/
Alerts the model if you choose a brand, then a model.

Try following steps,
on change of brands list make an ajax call and make sure in result you recieve the new list options or you can dynamically prepare the options list in jquery also.
And on success of call repopulate new list with the received data.
jQuery('.brands').change(function() {
var brand = jQuery('.brands option:selected').text();
brand = JSON.stringify(cleanString(brand));
$.ajax({
type: "GET", //GET or POST or PUT or DELETE verb
url: ajaxUrl, // Location of the service
data: brand , //Data sent to server
contentType: "", // content type sent to server
dataType: "json", //Expected data format from server
processdata: true, //True or False
success: function (data) {//On Successful service call
var $newList = $(".models select'").empty();
$newList.append(data);
},
error: function(){} // When Service call fails
});
});

Try the following:
/* using delegate version of .on */
jQuery(document).on('change', '.brands', function() {
var brand = jQuery('.brands option:selected').text();
brand = cleanString(brand);
jQuery('.models').load('/pf-models #' + brand);
});
jQuery(document).on('change', '.models select', function() {
var model = jQuery('.models option:selected').text();
model = cleanString(model);
jQuery('#show-models').load('/pf-urls #' + model);
});
For dealing with "dynamic" elements, you want to use delegate to assign action. This basically reserves a method to be assigned to all elements who match the description.
See also:
http://api.jquery.com/delegate/
http://api.jquery.com/on/#direct-and-delegated-events

Related

Issue with setting value to select dropdown in MVC

I am using MVC.
I am having two drop down and one change of 'primaryspec' the 'primarysubspec' should get loaded.
Everything is working fine for passing values to controller and it got saved to DB.
When I am trying to retrieve the saved details,'primarysubspec' saved values are not getting displayed.
But displaying save data for 'primarySpec'.
Here is my .cshtml code:
#Html.DropDownListFor(m => m.PSpec, Model.PSpec, new { id = "ddUserSpec", style = "width:245px;height:25px;", data_bind = "event: {change: primaryChanged}" }, Model.IsReadOnly)
#Html.DropDownListFor(m => m.PSubspec, Model.PSubspec, new { id = "ddUserSubSpec", style = "width:245px;height:25px;", data_bind = "options: primarySubSpec,optionsText: 'Name',optionsValue: 'Id'" }, Model.IsReadOnly)
Here is my JS Code to retrieve the values for :
this.primarySubSpec = ko.observableArray([]);
this.primarySpecChanged = function () {
var val = $("#ddetailsPrimarySpec").val();
primarySubStartIndex = 0;
primarySubSpecialityUrl = '/PlatformUser/GetSpecandSubSpec?primarySpe=' + val+//model.primarySpecID() +'&secondarySpec=';
loadPrimarySubSpec();
};
function loadPrimarySubSpec() {
$.ajax({
type: 'GET',
url: primarySubSpecUrl,
contentType: 'application/json; charset=utf-8',
dataType: 'json',
processdata: false,
cache: false,
success: function (data) {
primarySubSpec = [];
model.primarySubspec('0');
try {
if (data.length == 0) {
primarySubSpeacId.empty();
}
model.primarySubSpec(data);
},
error: function (request, status, error) {
primarySubSpeacId.prop("disabled", true);
}
});
}
Everything is working fine,but facing issue only while displaying the saved values from the DB.
Showing fine for 'primarySpec'
The values showing empty for 'PrimarySubSpec' instead of saved values in dropdown.
Please let me know what is the issue how can i show the saved value as selected value in 'primarySubSpec'dropdown.
The Problem:
when you load the page to view saved values, the change event is never called.
Why:
When your page is loaded with saved values, the select box has the saved value selected before knockout knows anything about it. Hens the change event isn't called.
Simplest solution:
change the primarySpecilaityChanged as follows
this.primarySpecilaityChanged = function () {
var val = $("#ddUserDetailsPrimarySpeciality").val();
if(val){
primarySubStartIndex = 0;
primarySubSpecialityUrl = '/' + NMCApp.getVirtualDirectoryName() + '/PlatformUser/GetSpecialitiesandSubSpecilaities?primarySpeciality=' + val+//model.primarySpecialityUID() +'&secondarySpeciality=';
loadPrimarySubSpecilaities();
}
};
then call primarySpecilaityChanged function after you call ko.applyBindings.
var viewModel = new YourViewModel();
ko.applyBindings(viewModel);
viewModel.primarySpecilaityChanged();

Duplication in HTML datalist using JQuery with more than one clicks

I design a datalist on web page. And I want to fill this datalist using JQuery. Controller execute a query and get a list of facilities. Then pass this list to client side. This datalist can show all the facilities. When user click this textbox, the facilities will be listed in drop down list. But when user click more than once, there will be duplicates in datalist. That means, if you click twice, the result will be shown twice in datalist.
Here is code in MVC view
datalist:
<input type="text" list="facility" autocomplete="on" name="Facility" id="facilities" />
<datalist id="facility"></datalist>
JQuery Code:
$(document).ready(function () {
$('#facilities').click(function () {
//alert("Clicked");
var postData = $('#clientTxt').val();
$.ajax({
type: "POST",
url: '#Url.Action("FacilityCheck", "PCA")',
data: { clientTxt: postData },
success: function (result) {
//successful
for (var i = 0; i < result.facilities.length; i++) {
//alert(JSON.stringify(result.facilities[i]));
var option = "<option value ='" + result.facilities[i] + "'>" + result.facilities[i] + "</option>";
//I want to add an if judgement to avoid duplicates here
//Like contains() method in JAVA.
$('#facility').append(option);
}
},
error: function (result) {
alert('Oh no :(');
}
});
});
});
The duplicates image after clicking many times:
So please give me some advice. Thanks a lot!
It is because you are using the jQuery append() method and not replacing the HTML. Right now, you're just adding (appending) to it every time you iterate through your loop of result.facilities[i] instead of replacing the content.
Your best bet would be to add all of that source to a string and replace the $('#facility')'s innerHTML with the new content. You can use $('#facility').html(yourContentString); to do so.
Hope this helps!
For example...
success: function (result) {
var options = "";
//successful
for (var i = 0; i < result.facilities.length; i++) {
var option = "<option value ='" + result.facilities[i] + "'>" + result.facilities[i] + "</option>";
options = options + option;
} //end of loop
$('#facility').html(options); // replace the innerHTML of #facility with your new options string
},
Simply modify your success like this :
$('#facility').html('');
$('#facility').append(option);
Remove the items before appending them.
You can also use empty :
$('#facility').empty();

AJAX Adding Multiple Events Resetting Id Before Insert

In Full Calendar, i have some droppable external items. When i drag and drop one of them and immediately i delete it, it gets deleted, everything works fine. However, when i drop multiple items, such as 2 and when i delete 2 of them, both gets removed from calendar in the view, actually one gets removed from database, if i refresh the page i can see that.
When i check the form input hidden's value which is event's id fetched from database or returned from database as last insert id via ajax, both are the same it seems, actually they are not the same.
I think what i need is, resetting the eventID variable after they got dragged and dropped. I tried to initiliza them as empty, but it doesn't work.
How can i reset their values after ajax submit for the next units, hence keeping that variable to attached to current. Also its a global variable, i think this is the problem.
My Codes:
var eventID; // global variable
Drop Function:
drop: function(date, allDay) {
var originalEventObject = $(this).data('eventObject');
// we need to copy it, so that multiple events don't have a reference to the same object
var copiedEventObject = $.extend({}, originalEventObject);
// assign it the date that was reported
copiedEventObject.start = date;
if($extraEventClass) copiedEventObject['className'] = [$extraEventClass];
var tempDate = new Date(date);
copiedEventObject.start = $.fullCalendar.formatDate(copiedEventObject.start, "yyyy-MM-dd HH:mm:ss");
eventID = '';
$.ajax({
url: '<?=site_url("admin/calendar/add");?>',
data: 'title='+ copiedEventObject.title,
type: "POST",
success: function(newID){
eventID = newID;
//copiedEventObject._id = newID;
}
});
calendar.fullCalendar('renderEvent',
{
title: copiedEventObject.title,
start: date,
//id: copiedEventObject._id,
id: eventID,
}),
true // make the event "stick"
}
Event Click Function:
eventClick: function(calEvent, jsEvent, view) {
if(!eventID){
eventID = calEvent._id;
}
var form = $("<form id='changeName'>" +
"<h3 class='eventHeader'>Edit</h3>" +
"</div></form>");
form.append("<div class='controls'>" +
"<label class='control-label' for='title'>Name: </label>" +
"<input class='span3' name='title' autocomplete=off type='text' value='" + calEvent.title + "' />" +
"</div>");
form.append("<input type=hidden value='" + eventID + "' /> ");
form.append("<div class='controls'>" +
"<button type='submit'> Save </button>");
var div = bootbox.dialog(form,
[
{
"label" : "Delete",
"callback": function() {
deleteOrNot = confirm("Sure ??");
if (deleteOrNot) {
calendar.fullCalendar('removeEvents' , function(ev){
$.ajax({
url: '<?=site_url("admin/calendar/delete");?>',
data: 'id='+ eventID,
type: "POST"
});
return (ev._id == calEvent._id);
})
}
}
}
]);
$("#changeName").submit(function() {
calEvent.title = form.find("input[name=title]").val();
calEvent.description = form.find("input[name=description]").val();
calEvent.id = form.find("input[type=hidden]").val();
$.ajax({
url: '<?=site_url("admin/calendar/editTitle");?>',
data: 'title='+ calEvent.title+'&id='+ calEvent.id,
type: "POST"
});
calendar.fullCalendar('updateEvent', calEvent);
div.modal("hide");
return false;
});
}
In your delete process...you shouldn't be relying on the global eventID, rather just getting the ID from specific event
Change:
if(!eventID){
eventID = calEvent._id;
}
To:
var eventID = calEvent._id;
I suspect you also have a problem within drop by using the global eventID when dropping more than one at a time. Would have to see what // some methods here does.
What I would suggest is getting rid of the global eventID completely. When adding, wait for the id to be returned from server before passing the data to fullCalandar within your success callback
Similarly...within deleteOrNot...should make ajax request first, then only call the calendar.fullCalendar('removeEvents' within success callback of $.ajax. This will give confirmation of ajax success before user sees event removed. If ajax fails, user won't know using your approach

jQuery - proper way to create plugin

I'm trying to convert some of my code to reusable plugins.
Many times I'm filling selects with dynamic options that comes from Ajax request.
I've managed to create something like this:
$.fn.fillSelect = function fillSelect(options) {
var self = this;
options = $.extend({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "Data.asmx/StatusList",
dataType: "json",
async: true,
success: function(data) {
var list = "";
$.each(data.d, function(i) {
list += '<option value='
+ data.d[i].ID + '>'
+ data.d[i].Nazwa
+ '</option>';
});
self.filter("select").each(function() {
$(this).empty();
$(this).append(list);
//use selectmenu
if ($.ui.selectmenu) $(this).selectmenu();
});
}//,
//error: function(result) {
// alert("Error loading data!");
//}
}, options);
$.ajax(options);
return self;
}
Idea behind this is to be able to fill multiple selects with the same data multiple times with one request.
I have default options for Ajax request, but I would like to add some more options to it.
For example:
clear - fill determinate if I want new options to replace existing ones or append.
Also I would like to add some callbacks to my function that I could pass as parameters.
If for example server request will fail I would like to specify a function that will be called after this error occurs - for example to show alert or disable my selects.
My question is how should I change my plugin or which pattern (boilerplate) I should use?
Every boilerplate I found is for creating plugins that will 'stay' inside selected item, so that it is possible to call method of that plugin later.
I need a simple plugin that will allow user to fill select and then it will end it's life :)
My main idea is to do only one request to server for all elements.
Here is jsfiddle demo: http://jsfiddle.net/JC7vX/2/
A basic plugin can be built as follows
(function ($){
$.fn.yourPlugin = function (options){
// this ensures that function chaining can continue
return this.each(function (){
// merge defaults and user defined options
var params = $.extend({},defaultOptions,options);
// your plugin code
});
}
/* these options will help define the standard functionality of the plugin,
* and also serves as a nice reference
*/
var defaultOptions = {
someProperty : true
}
})(jQuery)
There are other things that you can do to extend the functionality of your plugin and give public methods that retain the context, but that would be overkill for your example.
This is my version of answer http://jsfiddle.net/Misiu/ncWEw/
My plugin looks like this:
(function($) {
$.fn.ajaxSelect = function(options) {
var $this = this;
//options
var settings = $.extend({}, defaults, options);
//disable select
if ($.ui.selectmenu && settings.selectmenu && settings.disableOnLoad) {
$this.selectmenu('disable');
}
//ajax call
$.ajax({
type: settings.type,
contentType: settings.contentType,
url: settings.url,
dataType: settings.dataType,
data: settings.data
}).done(function(data) {
var n = data.d || data;
var list = "";
$.each(n, function(i) {
list += '<option value=' + n[i].Id + '>' + n[i].Nazwa + '</option>';
});
$this.filter("select").each(function() {
$(this).empty();
$(this).append(list);
if ($.ui.selectmenu && settings.selectmenu) {
$this.selectmenu();
}
settings.success.call(this);
});
}).fail(function() {
settings.error.call(this);
});
return this;
};
var defaults = {
type: "POST",
contentType: "application/json; charset=utf-8",
url: '/echo/json/',
dataType: 'json',
data: null,
async: true,
selectmenu: true,
disableOnLoad: true,
success: function() {},
error: function() {}
};
})(jQuery);
I understand that it is very simple, but it has all functionality that I needed:
-You can select multiple elements at one time
-It filters only selects from Your selected items
-It makes only one request to server
-First it builds option string and then append it instead of adding items in loop
-You can specify 2 callbacks: one for error and second for success
And it is my first plugin, so there is much places for improvements.
As always comments and hints are welcome!

Convert function into plugin

I have a function that I call multiple times in my projects:
function fillSelect(select) {
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "Data.asmx/Status",
dataType: "json",
async: true,
success: function(data) {
$.each(data.d, function(i) {
select.append('<option value=' + data.d[i].value + '>' + data.d[i].name + '</option>');
});
},
error: function(result) {
alert("Error occured. Contact admin");
}
});
}
Then in my code I'm using this like so:
fillSelect($('select#status1'));
fillSelect($('select#status2'));
fillSelect($('select#status3'));
What I would like to do is to convert my function into plugin, so I would be able to call it as so:
$('select#status1, select#status2, select#status3').fillSelect();
Using http://starter.pixelgraphics.us/ I've generated empty schema:
(function($) {
$.ajaxSelect = function(el, select, options) {
// To avoid scope issues, use 'base' instead of 'this'
// to reference this class from internal events and functions.
var base = this;
// Access to jQuery and DOM versions of element
base.$el = $(el);
base.el = el;
// Add a reverse reference to the DOM object
base.$el.data("ajaxSelect", base);
base.init = function() {
base.select = select;
base.options = $.extend({}, $.ajaxSelect.defaultOptions, options);
// Put your initialization code here
};
// Sample Function, Uncomment to use
// base.functionName = function(paramaters){
//
// };
// Run initializer
base.init();
};
$.ajaxSelect.defaultOptions = {
clear: false //append to select or replace current items
};
$.fn.ajaxSelect = function(select, options) {
return this.each(function() {
(new $.ajaxSelect(this, select, options));
});
};
})(jQuery);
but I don't know how to fill it.
What I would like to do is to call sever ones and then fill as many select items as I put in parameters.
Is all that code really necessary for such a small plugin?
I know that there are probably some plugins that this functionality, but I would like to create my own plugin, just to learn a bit more :)
You don't need all that boiler plate you could do as below
$.fn.fill = function fillSelect(options) {
var self = this;
options = $.extend({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "Data.asmx/Status",
dataType: "json",
async: true,
success: function(data) {
var list = "";
$.each(data.d, function(i) {
list += '<option value='
+ data.d[i].value + '>'
+ data.d[i].name
+ '</option>';
});
self.filter("select").each(function(){
$(this).append(list);
});
},
error: function(result) {
alert("Error occured. Contact admin");
}
},options);
$.ajax(options);
return this;
}
the first thing to notice that the function is added to the jQuery prototype/$.fn. Then the success handler have been changed so that all selected elements will be handled and lastly the selection is returned to make chaining possible, as this is usually expect when using jQuery.
The above code will append the same options to all selected "select" elements only. If you select something else the options will not be appended to those elements.
I've changed the signature to accept an options element. In the above version there's default vesrion equaling your ajax options. If other values are supplied, they will override the default ones if a default exist. If a default does not exist the values will be added to the options object
You just need to add your method to the $.fn object, as described here: http://docs.jquery.com/Plugins/Authoring
The this keyword will evaluate to the jQuery selector that was used to invoke your function's code, so instead of using the select parameter in your code, just use this

Categories

Resources