jQuery Wait for select to populate from database - javascript

I have ddl(drop down list) which populates from database after change event of another ddl but I want to change the value of this ddl after it populated from database.
Example:
// This work very well
$("#ddlGroups").on('change',function(){
// Load data from database and populate ddlUsers
// response is loaded from database with $.ajax
// Query Example: SELECT User_ID, Username FROM tblUsers WHERE Group_ID = [Group_ID] (Just for undrestanding the question)
var Records = response.d;
$("#ddlUsers").empty();
$.each(Records, function(){
var _Key = this.User_ID;
_Value = this.Username;
$("#ddlUsers").append($("<option />").val(_Key).text(_Value));
});
});
// When button clicked then trigger ddlGroups change event and assign select option from ddlUsers
var _UserID = User_ID_From_Database; // Loaded from Database when button clicked
$("#ddlGroups").trigger('change'); // Users are loaded from database based on group ID
$("#ddlUsers").val(_UserID); // But this dosn't change
How do I check if ddlUsers is loaded or not, I tried while loop but it never stops.

With jquery there are two main ways (really the same underlying) to connect a ajax response from the database to a event or UI result. The first is promises and the second is a callback. Both these have 1 million examples and jquery documentation is quite robust.
In your case rather than "trigger", you callback calls the right function. The below is just junk code to show.
No: $("#ddlGroups").tigger('change');
Yes:
//Your code
$("#ddlGroups").on('change', updateDDL);
//I have just externalized this function to a scope/place where both the ajax and on change line of code can reference it.
function updateDDL(){
var Records = response.d;
$("#ddlUsers").empty();
$.each(Records, function(){
var _Key = this.User_ID;
_Value = this.Username;
$("#ddlUsers").append($("<option />").val(_Key).text(_Value));
}
};
$.ajax(...., function (data) {
// Update ddl, the existing function you have.
// You should already have something like this.
updateDDL(); //Like this
});
BTW: You could pass the data into the updateDDL directly use $(this) in the updateDDL to improve it etc but that is not key to your question/issue. It seems that you are new to jquery and some of the Javascript features it uses. Take a little time to learn about them and you will be WELL rewarded. I would start by reading examples around ajax/jquery and watch how then update the DOM.

Related

Problem selecting an item after building the select options with AJAX

I use this javascript to select a specific option (the option value being specified within a hidden element):
$("select").each(function() {
var id = $(this).attr('id');
var source = 'input:hidden[name=select_'+id+']';
if ($(source).length) {
var selected = $(source).val();
$(this).val(selected).change();
}
});
This works fine when the options are hard coded in the HTML source.
I now need to populate the options with an AJAX call, I use the below method:
select : function(ctrl,id) {
var call = '/'+ctrl+'/'+$("#auth input[name=verify]").val();
$.getJSON(call, function(result) {
$.each(result, function() {
$('#'+id).append($("<option />").val(this.id).text(this.title));
});
});
},
I process the select method (AJAX) on page load, and the options populate fine. But when I then try to select the desired option, the browser defaults to the first option.
I have tested what is happening by sticking some alerts around the code as thus:
alert($(this).val(selected)); // A
alert($(this).val()); // B
$(this).val(selected).change();
alert($(this).val()); // C
When the options are hard coded I get A=3, B=null, C=3 i.e. it works
When the options are populated via AJAX I get A=3, B=null, C=null i.e. it fails
I am guessing that I need to trigger some kind of change() event after populating the option list with AJAX. I have tried (a bit overkill I know):
$('#'+id).append($("<option />").val(this.id).text(this.title).change());
&
$('#'+id).append($("<option />").val(this.id).text(this.title)).change();
Any ideas? Thx
Problem solved.
Although I was triggering the code in the correct order (in theory), because of javascripts event driven behaviour the AJAX call was not completing until after my select initialisation had finished. So I moved the code to set the selected option into the AJAX call and voila.
select : function(ctrl,id) {
var call = '/'+ctrl+'/'+$("#auth input[name=verify]").val();
$.getJSON(call, function(result) {
$.each(result, function() {
$('#'+id).append($("<option />").val(this.id).text(this.title));
});
var source = 'input:hidden[name=select_'+id+']';
if ($(source).length) {
var selected = $(source).val();
$('#'+id).val(selected).change();
}
});

Execute DataTables ajax.reload() Async before a function

I am trying to source some data from the datatable I am working on. I have an edit button on every row and when is clicked it suppose to bring a form with the data that is already in the table for editing. I need to get real time data when the form is render however ajax.reload() doesn't load the table on time for the form be filled by the correct data and with code below only shows the form for the first employee:
let editEmployeeId;
$(document).ajaxStop(function(){
$('#employeesTable tbody').on('click', '.btn.btn-warning.small-edit-button', function(){
let thisRow = this;
tableEmployees.ajax.reload(function(){
//tableDepartments.draw();
tableDepartments.columns().search("").draw();
//tableEmployees.columns().search("").draw();
getDropdown(1,'#departmentEditDropdown', 'Departments');
var data = tableEmployees.row($(thisRow).parents('tr')).data() || tableEmployees.row($(thisRow).parents('li').attr('data-dt-row')).data();
$('#editFirstName').val(data.firstName);
$('#editLastName').val(data.lastName);
$('#departmentEditDropdown>select').val(data.department);
updateLocation('#locationEditDropdown','#departmentEditDropdown>select');
$('#departmentEditDropdown>select').trigger('change');
$('#locationEditDropdown>select').val(data.locationID);
$('#editJobTitle').val(data.jobTitle);
$('#editEmail').val(data.email);
$('#editEmployeeModal').modal("show");
});
});
I tried:
promise
settimeout
nested functions
async functions
I also try to change ajax call to set async: false and this way it works perfect but I don't think that is a good practice and I have other calls through the document and takes double of time to load the page first time.
I changed the way of calling the button with an extra class for the employees page and used the .click() method instead .on() because for some reason it was going in a loop with the last one. Now works and this is how it looks:
let editEmployeeId;
$(document).ajaxStop(function(){
$('.btn.btn-warning.small-edit-button.employees').click(function(e){
e.preventDefault();
let thisRow = tableEmployees.row($(this).parents('tr'));
let thatRow = tableEmployees.row($(this).parents('li').attr('data-dt-row'));
tableDepartments.columns().search("").draw();
tableEmployees.columns().search("").draw();
getDropdown(1,'#departmentEditDropdown', 'Departments');
tableEmployees.ajax.reload(function(){
var data = thisRow.data() || thatRow.data();
editEmployeeId = data.id;
$('#editFirstName').val(data.firstName);
$('#editLastName').val(data.lastName);
$('#departmentEditDropdown>select').val(data.department);
$('#departmentEditDropdown>select').trigger('change');
$('#editJobTitle').val(data.jobTitle);
$('#editEmail').val(data.email);
$('#editEmployeeModal').modal("show");
})
});

Two-way data binding for a Meteor app

I've built an app that is form-based. I want to enable users to partially fill out a form, and then come back to it at a later date if they can't finish it at the present. I've used iron router to create a unique URL for each form instance, so they can come back to the link. My problem is that Meteor doesn't automatically save the values in the inputs, and the form comes up blank when it is revisited/refreshes. I tried the below solution to store the data in a temporary document in a separate Mongo collection called "NewScreen", and then reference that document every time the template is (re)rendered to auto fill the form. However, I keep getting an error that the element I'm trying to reference is "undefined". The weird thing is that sometimes it works, sometimes it doesn't. I've tried setting a recursive setTimeout function, but on the times it fails, that doesn't work either. Any insight would be greatly appreciated. Or, if I'm going about this all wrong, feel free to suggest a different approach:
Screens = new Meteor.Collection('screens') //where data will ultimately be stored
Forms = new Meteor.Collection('forms') //Meteor pulls form questions from here
NewScreen = new Meteor.Collection('newscreen') //temporary storage collection
Roles = new Meteor.Collection('roles'); //displays list of metadata about screens in a dashboard
//dynamic routing for unique instance of blank form
Router.route('/forms/:_id', {
name: 'BlankForm',
data: function(){
return NewScreen.findOne({_id: this.params._id});
}
});
//onRendered function to pull data from NewScreen collection (this is where I get the error)
Template.BlankForm.onRendered(function(){
var new_screen = NewScreen.findOne({_id: window.location.href.split('/')[window.location.href.split('/').length-1]})
function do_work(){
if(typeof new_screen === 'undefined'){
console.log('waiting...');
Meteor.setTimeout(do_work, 100);
}else{
$('input')[0].value = new_screen.first;
for(i=0;i<new_screen.answers.length;i++){
$('textarea')[i].value = new_screen.answers[i];
}
}
}
do_work();
});
//onChange event that updates the NewScreen document when user updates value of input in the form
'change [id="on-change"]': function(e, tmpl){
var screen_data = [];
var name = $('input')[0].value;
for(i=0; i<$('textarea').length;i++){
screen_data.push($('textarea')[i].value);
}
Session.set("updateNewScreen", this._id);
NewScreen.update(
Session.get("updateNewScreen"),
{$set:
{
answers: screen_data,
first: name
}
});
console.log(screen_data);
}
If you get undefined that could mean findOne() did not find the newscreen with the Id that was passed in from the url. To investigate this, add an extra line like console.log(window.location.href.split('/')[window.location.href.split('/').length-1], JSON.stringify(new_screen));
This will give you both the Id from the url and the new_screen that was found.
I would recommend using Router.current().location.get().path instead of window.location.href since you use IR.
And if you're looking for two way binding in the client, have a look at Viewmodel for Meteor.

Use jQuery to determine when Django's filter_horizontal changes and then get the new data

I have a filter_horizontal selector in my Django admin that has a list of categories for products (this is on a product page in the admin). I want to change how the product change form looks based on the category or categories that are chosen in the filter_horizontal box.
I want to call a function every time a category is moved from the from or to section of the filter_horizontal.
What I have now is:
(function($){
$(document).ready(function(){
function toggleAttributeSection(choices) {
$.getJSON('/ajax/category-type/', { id: choices}, function (data, jqXHR) {
// check the data and make changes according to the choices
});
}
// The id in the assignment below is correct, but maybe I need to add option[]??
var $category = $('#id_category_to');
$category.change(function(){
toggleAttributeSection($(this).val());
});
});
})(django.jQuery);
The function never gets called when I move categories from the left side to the right side, or vice versa, of the filter_horizontal.
I assume that $category.change() is not correct, but I don't know what other events might be triggered when the filter_horizontal is changed. Also, I know there are multiple options inside of the select box. I haven't gotten that far yet, but how do I ensure all of them are passed to the function?
If anyone can point me in the right direction I would be very grateful. Thank!
You need to extend the SelectBox.redisplay function in a scope like so:
(function() {
var oldRedisplay = SelectBox.redisplay;
SelectBox.redisplay = function(id) {
oldRedisplay.call(this, id);
// do something
};
})();
Make sure to apply this after SelectBox has been initialized on the page and every time a select box refreshes (option moves, filter is added, etc.) your new function will be called.
(Code courtesy of Cork on #jquery)
I finally figured this out. Here is how it is done if anyone stumbles on this question. You need to listen for change events on both the _from and _to fields in the Django filter_horizontal and use a timeout to allow the Django javascript to finish running before you pull the contents of the _from or _to fields. Here is the code that worked for me:
var $category = $('#id_category_to');
$category.change(function(){
setTimeout(function () { toggleAttributeSection(getFilterCategoryIds()) }, 500);
});
var $avail_category = $('#id_category_from');
$avail_category.change(function(){
setTimeout(function () { toggleAttributeSection(getFilterCategoryIds()) }, 500);
});
And this is how I get the contents of the _to field:
function getFilterCategoryIds() {
var x = document.getElementById("id_category_to");
var counti;
var ids = [];
for (counti = 0; counti < x.length; counti++) {
ids.push(x.options[counti].value);
}
return ids;
}
I know it was a convoluted question and answer and people won't come across this often but hopefully it helps someone out.

jsTree: how to select node after refresh

I have a jQuery jsTree populated from the server via an ajax call. When I add a new node I make an ajax call then make a call to refresh the tree with tree.jstree("refresh"). After the refresh I want to select the node I just added. Unfortunately there doesn't seem to be a callback that can be passed to this command. Is there any clean way to do this?
oh, such a long time since this post ... and still couldn't find an answer on internet.
So after a few hours of ... no no no, not this, came up with a solutin
var jsTreeId = '#jstree'; // or whatever name the jstree has
var jsTreeSelectedItemId = 5; // just an example
var selectedNode = $('#node_'+jsTreeSelectedItemId);
var parentNode = $.jstree._reference(jsTreeId)._get_parent(selectedNode);
// now lets say that you add a new node from server side, you get the new id of the created node by an ajax call, and next you want to refresh the tree in order to display it, and also select it
var newSelectId = 9; // or from ajax call
// call the refresh function, which is asnyc
$.jstree._reference(jsTreeId).refresh(parentNode);
// set the magic "to_select" variable with an array of node ids to be selected
// note: this must be set after refresh is called, otherwise won't work
$.jstree._reference(jsTreeId).data.ui.to_select = ['#node_'+newSelectId];
$('#tree').jstree("select_node", '#1', true);
//other node are deselected if pass last argument as true.
$('#tree').jstree("select_node", '#1', false);
//other node are selected and new one also selected.

Categories