Hi StackOverflow and fellow developers...
So. I really enjoy Materialize CSS, but it can get to my head sometimes.
I have some select elements on my site, which is very nice, and the initialization works fine and they are displayed.
I then have another function to populate the selects, and according to the Materialize documentation i should just run $('select').material_select();again. Unfortunately when i try to call the function for the second time i get the error Uncaught TypeError: $(...).material_select is not a function.
I can't understand why i can't call the function when i just did in the document ready function?
JS Bundle For Page:
Blockquote
$(document).ready(function () {
// This works fine and as expected my Selects are rendered perfect
$('select').material_select();
fetchSoftware();
getusersinit();
});
var fetchSoftware = function fetchSoftware() {
$.ajax({
type: "Get",
url: "Dashboard/GetSoftwares",
data: { userName: "*****" },
success: function success(softwares) {
console.log(softwares);
$("#softwareSelectDefault").remove();
Object.keys(softwares).forEach(function (key) {
$("#softwareSelect").append("<option>" + softwares[key] + "</option>");
});
//Down here shit falls apart. This doesen't work
$('select').material_select();
},
error: function error(errorMessage) {
//window.location.href = "/account/signin";
}
});
};
var getusersinit = function getusersinit() {
$.ajax({
type: "Get",
url: "***********",
data: { userName: "**********" },
success: function success(reports) {
console.log(reports);
$(".progress").remove();
Object.keys(reports).forEach(function (key) {
$("#******").append("<tr id=\"" + reports[key].id + "\"><td><i class=\"medium material-icons\">" + reports[key].locked + "</i></td><td><i class=\"medium material-icons\">" + reports[key].status + "</i></td><td>" + reports[key].user + "</td><td>" + reports[key].script + "</td><td>" + reports[key].software + "</td><td>" + reports[key].testBench + "</td><td>" + reports[key].repository + "</td><td>" + reports[key].executionTime + "</td><td>" + reports[key].startDate + "</td></tr>");
});
},
error: function error(errorMessage) {
window.location.href = "/account/signin";
}
});
};
Update 10-04-2018
So, after spending almost the whole workday yesterday on this problem, I'm now a little closer to a solution.
I discovered something very strange. Apparently, the problem lies in my ajax call. I have a theory, that it depends on the url or reply.
$(document).ready(function () {
//fetchSoftware works. If i run getuserinit it does not. Then material_select doesen't exist
fetchSoftware();
});
var fetchSoftware = function fetchSoftware() {
$.ajax({
type: "Get",
url: "https://jsonplaceholder.typicode.com/posts/1",
data: { userName: "XXXXXX" },
success: function (result) {
$("#testReports").append(`<tr><td>TEST</td></tr>`);
$("#softwareSelect").append(`<option>Test Option</option>`);
$('#softwareSelect').material_select();
},
error: (errorMessage) => {
window.location.href = "/account/signin";
}
});
};
var getusersinit = function getuserinit() {
$.ajax({
type: "Get",
url: "Dashboard/LoadTable",
data: { userName: "XXXXXX" },
success: function (result) {
$("#testReports").append(`<tr><td>TEST</td></tr>`);
$("#softwareSelect").append(`<option>Test Option</option>`);
$('#softwareSelect').material_select();
},
error: (errorMessage) => {
window.location.href = "/account/signin";
}
});
};
formSelect() is the new method.
Use selectSoftware.formSelect(); instead of material_select()
I fixed the issue, though it is a workaround.
Put the selects in variables...
/*
These constant are created because of an unsolved issue:
See https://stackoverflow.com/questions/49728000/
By putting the selects into constants, and only referencing the constants,
this is a workaround.
*/
var selectSoftware = $('#softwareSelect');
$(document).ready(function () {
selectSoftware.material_select();
getSoftware();
});
var getSoftware = function getSoftware() {
$.ajax({
type: "Get",
url: "Dashboard/GetSoftwares",
data: { userName: "XXXXXXX" },
success: function success(softwares) {
console.log(softwares);
$("#softwareSelectDefault").remove();
Object.keys(softwares).forEach(function (key) {
$("#softwareSelect").append("<option>" + softwares[key] + "</option>");
});
selectSoftware.material_select();
},
error: function error(errorMessage) {
//window.location.href = "/account/signin";
}
});
};
Related
I have three relational dropdown like if i select the program dropdown then it should populate the years and when i select the year it should populate blocks , i wrote the javascript for it it is working fine but there is an issue like on page load the events are not fired i need to select the dropdown list value and then change it to fire the event secondly on third dropdown its value did not get refreshed when i changed the dropdown of first dropdown list can someone suggest me how to fix these two issues
below is my code
$("#ddlProgram").change(function () {
$("#ddlYear").empty();
$.ajax({
type: 'POST',
url: '#Url.Action("getCity")',
dataType: 'json',
data: { id: $("#ddlProgram").val() },
success: function (states) {
$.each(states, function (i, state) {
$("#ddlYear").append('<option value="' + state.Value + '">' +
state.Text + '</option>');
});
},
error: function (ex) {
alert('Failed to retrieve Year information.' + ex);
}
});
return false;
})
});
</script>
<script type="text/javascript">
$(document).ready(function () {
$("#ddlYear").change(function () {
$("#ddlBlock").empty();
$.ajax({
type: 'POST',
url: '#Url.Action("getBlocks")',
dataType: 'json',
data: {
id: $("#ddlYear").val(),
programid: $("#ddlProgram").val()
},
success: function (states) {
$.each(states, function (i, state) {
$("#ddlBlock").append('<option value="' + state.Value + '">' +
state.Text + '</option>');
});
},
error: function (ex) {
alert('Failed to retrieve information.' + ex);
}
});
return false;
})
});
</script>```
I have created a jQuery function extending its own object $. This function translate those elements attached to the element this:
$.fn.extend({
translate: function(sourceLang, targetLang) {
if($(this).text().trim().length < 1 || !isNaN(parseInt($(this).text().trim())) || sourceLang == targetLang)
return;
let $function = this;
$($function).each(function() {
let $each = this;
$.ajax({
url: 'https://translate.yandex.net/api/v1.5/tr.json/translate',
method: 'GET',
dataType: 'JSONP',
crossDomain: true,
data: {
key: /* my-secret-key */,
text: $($each).text(),
lang: sourceLang + '-' + targetLang
},
success: function(response) {
try {
if(response.code !== 200)
throw "Response: " + response.code;
$($each).text(response.text[0])
} catch(error) {
console.error('Translation error on element: ', $($function).text());
console.error('Message returned by the server:', error);
}
},
error: function(xhr, status, error) {
console.error('Translation error on element: ', $($function).text());
console.error('Message returned by the server:', xhr.responseText);
}
});
});
}
});
After loading the code I do this:
$(document).ready(function() {
let lang = $('html').attr('lang').split('-')[0];
$('td td:visible').translate(lang, "en");
});
Note: the HTML tag looks like this <html lang="es-ES"> depending on the logged user language.
The issue I have is the table loads after a couple of seconds (since we are not in Production environment they could be more than 30). Therefore the previous code block is not useful.
Note: the <tbody> tag is created when the data is added.
What I have tried is:
1. Create a setInterval() and clearInterval() when the $('td:visible').length is greater than 0:
let iv = setInterval(function() {
let lang = $('html').attr('lang').split('-')[0];
let rows = $('tbody td:visible');
if(rows.length > 0) {
rows.translate(lang, "en");
clearInterval(iv);
}
}, 1000);
2. Set a .delay() before the translation:
let isTranslated = false;
while(!isTranslated) {
let lang = $('html').attr('lang').split('-')[0];
let rows = $('tbody td:visible');
if(rows.length > 0) {
rows.delay(1000).translate(lang, "en");
isTranslated = true;
}
}
The memory consumed by the browser is greater than 200MB. I also tried with $('table').on('DOMSubstreeModified', 'tbody', function() {}) but it didn't work.
So, what approach would you recommend to use this translation plugin on this table after it loads its tbody?
Edit 1:
I have changed my code so I perform less API requests, thanks to the recommendation of #lucifer63:
let $function = this;
let collection = [];
let translation = '';
$(this).each(function() {
collection.push($(this).text());
});
let text = collection.join('::');
$.ajax({
url: 'https://translate.yandex.net/api/v1.5/tr.json/translate',
method: 'GET',
dataType: 'JSONP',
crossDomain: true,
data: {
key: /* my-secret-key */,
text: text,
lang: sourceLang + '-' + targetLang
},
success: function(response) {
try {
if(response.code !== 200) {
throw "Response: " + response.code;
}
translation = response.text[0].split('::');
$($function).each(function() {
$(this).text(translation.shift());
});
} catch(error) {
console.error('Message returned by the server:', error);
}
},
error: function(xhr, status, error) {
console.error('Message returned by the server:', xhr.responseText);
}
});
But still, I need to figure out how to print after data has loaded.
Well... I think I found the answer I was seeking:
$('body').on('DOMNodeInserted', 'table', function() {
$('td:visible').translate('es', 'en');
});
It seems it is working correctly.
$(document).ready(function () {
setInterval(function () {
$('#RoomBlock').children('div').each(function () {
ShowRoom($(this).attr('id'));
});
}, 10000);
function ShowRoom(id) {
$.ajax({
type: "POST",
url: "/localhost/GetData/" + id
success: function (response) {
if (response != null) {
$('#' + id).empty();
$('#' + id).append(response);
} else {
alert("null");
}
},
error: function (response) {
alert("error!");
}
});
})
i have 5 table and they always fetch data from server for several time, success times for every table is different, i want to put some loading bar on every table when they make a request. is there any way to do that with javascript ?
the one that make confuse is how to know that the first table is make a request and still while the other one was done.
try something like below
$(document).ready(function () {
setInterval(function () {
$('#RoomBlock').children('div').each(function () {
ShowRoom($(this).attr('id'));
});
}, 10000);
function ShowRoom(id) {
/* Add some loader here (bar or image)*/
var loaderHtml = "<div id='loader_'+id>_____Add your loader code here_____</div>";
$('#' + id).append(loaderHtml);
$.ajax({
type: "POST",
async: false,
url: "/localhost/GetData/" + id
success: function (response) {
if (response != null) {
$('#' + id).empty();
$('#loader_'+ id).remove();
$('#' + id).append(response);
} else {
alert("null");
$('#loader_'+ id).remove();
}
},
error: function (response) {
alert("error!");
}
});
})
I'm using asp.net webservice to use it in jQuery UI autocomplete plugin and here is the data I'm getting.
{"d":[
{
"__type":"WebS.Model.SearchModel",
"MainCommodityId":1,
"MainCommodityName":"Pulses",
"SubcommodityId":3,
"SubCommodityName":"Urid Dal",
"BrandId":3,
"BrandName":"President"
},
{
"__type":"WebS.Model.SearchModel",
"MainCommodityId":1,
"MainCommodityName":"Pulses",
"SubcommodityId":1,
"SubCommodityName":"Red Gram",
"BrandId":4,
"BrandName":"President"
}
]
}
This is the script I'm using:
$(document).ready(function () {
$(".input-search").autocomplete({
source: function (request, response) {
$.ajax({
url: '/WebServices/GetAllBrandNames.asmx/getAllBrands',
data: "{ 'data': '" + request.term + "'}",
dataType: "json",
contentType: "application/json; charset=utf-8",
type: "POST",
contentType: "application/json; charset=utf-8",
success: function (data) {
response($.map(data.d, function (item) {
return {
value: item.BrandName,
label: item.SubCommodityName
}
}))
},
error: function (response) {
alert('error');
},
failure: function (response) {
alert('faii');
}
});
},
select: function (e, i) {
console.log(i.MainCommodityId);
console.log(i.SubcommodityId);
console.log(i.BrandId);
},
minLength: 1
}).autocomplete("instance")._renderItem = function (ul, item) {
return $("<li></li>")
.data("item.autocomplete", item)
.append("<a>" + "" + item.BrandName + " in " + item.MainCommodityName + " - " + item.SubCommodityName + "</a>")
.appendTo(ul);
};
});
The issues are:
When I tried to enter keyword say: pre the aforesaid output is coming in json. However, the list is returning only one "President" item where it should display 2 items.
The list is displaying "undefined in undefined - undefined" instead of values after adding .autocomplete("instance")._renderItem function.
console.logs are also undefined after selecting an item.
How can these issues fixed?
The default behavior of the select event is to update the input with ui.item.value. This code runs after your event handler.
Simply prevent the default action on select and focus using event.preventDefault() or by return false and use _renderItem for custom dropdown.
focus: function(event, ui) {
// prevent autocomplete from updating the textbox
event.preventDefault(); // or return false;
}
select: function(event, ui) {
// prevent autocomplete from updating the textbox
event.preventDefault();
//do something
}
References:
jQuery UI Autocomplete Examples
Example 2
Finally, I was able to achieve what I wanted. Answering my question as it may helpful to someone.
javascript:
$(document).ready(function () {
$(".input-search").autocomplete({
source: function (request, response) {
$.ajax({
url: '/WebServices/GetAllBrandNames.asmx/getAllBrands',
data: "{ 'data': '" + request.term + "'}",
dataType: "json",
type: "POST",
contentType: "application/json; charset=utf-8",
success: function (data) {
response($.map(data.d, function (item) {
// don't forget to $.map to (data.d where d is the top node
return {
// assign values from json response for further use
brandid: item.BrandId,
brand: item.BrandName,
maincommodityid: item.MainCommodityId,
maincommodity: item.MainCommodityName,
subcommodityid: item.SubcommodityId,
subcommodity: item.SubCommodityName
}
}));
},
error: function (response) {
alert('Server Error. Please try again.');
},
failure: function (response) {
alert('Failed to get result');
}
});
},
focus: function (event, ui) {
// prevent autocomplete from updating the textbox
event.preventDefault();
},
select: function (event, ui) {
// prevent autocomplete from updating the textbox
event.preventDefault();
// do further action here such as assigning id to hidden field etc.
$(".input-search").val(ui.item.brand);
// navigate to the selected item's url ex: /catalogue/1/1/pulses/red-gram/4/president
var str = "/catalogue/" + ui.item.maincommodityid + "/" +
ui.item.subcommodityid + "/" + $.trim(ui.item.maincommodity.replace(/\s+/g, '-').toLowerCase()) + "/" +
$.trim(ui.item.subcommodity.replace(/\s+/g, '-').toLowerCase()) + "/" + ui.item.brandid + "/" +
$.trim(ui.item.brand.replace(/\s+/g, '-').toLowerCase());
window.location = str;
},
minLength: 3
}).autocomplete("instance")._renderItem = function (ul, item) {
// get values and create custom display
var $a = $("<a></a>");
$("<strong></strong>").text(item.brand).appendTo($a);
$("<span></span>").text(" in ").appendTo($a);
$("<span></span>").text(item.subcommodity).appendTo($a);
return $("<li></li>").append($a).appendTo(ul);
};
});
CSS:
ul.ui-front {
z-index: 1200; // change z-index according to your UI.
}
Usually I do this way and Its work.
$(document).ready(function () {
var jsondata=array();
$.post("/WebServices/GetAllBrandNames.asmx/getAllBrands",{data: request.term},function(data){
var data=JSON.parse(data);
$.each(data.d, function( index, value ) {
jsondata[index].value=value;
});
$(".input-search").autocomplete({
source:jsondata,
//other property and events
})
});
I mean apply source JSON after completing request because sometimes if AJAX takes some time to load execution pointer still execute rest of code without waiting for response.
I did not test this code but I always do this way and never get your kind of error. Good Luck
I'm faced with trying to add testing to a lot of code like the following. I know I can use mockjax to to intercept the ajax calls. But I don't how to test the $.ajax({...}) calls in isolation. I'd appreciate a good refactoring approach, but I'd also like to avoid rewriting the entire app.
I've gotten a start in other areas using qunit, and I like it. But I'm open to other suggestions too. How should I proceed?
function submitSync(repFrom, continuousRep, storedPassword) {
// var repTriggered = false;
if (repFrom !== '' && (storedPassword !== null || storedPassword !== "")) {
var secureHome = "http://" + homeUser + ":" + storedPassword + "#" + window.location.host + "/" + homeURL;
var theSource = repFrom.split("/");
var singleDocumentReplication = (theSource.length === 5);
/*
* DELETE existing replications. There will normally be no more than 1.
* Do not delete replications for application updates.
* Note that we don't allow the user to create continuous replications.
*/
$.getJSON(currentHost + '/_replicator/_all_docs', function (data) {
$.each(data.rows, function (i, theRow) {
$.ajax({
url: currentHost + '/_replicator/' + theRow.id,
type: "GET",
dataType: 'json',
async: false,
contentType: "application/json",
success: function (doc) {
if (doc._id !== "_design/_replicator" && (typeof doc.source !== 'undefined' && !doc.source.match(onlineBase + '/' + remoteDB))) {
$.ajax({
url: "/_replicator/" + doc._id + "?rev=" + doc._rev,
type: "DELETE",
contentType: "application/json",
success: function () {
console.log('Replication deleted: ' + doc._id + '?rev=' + doc._rev);
}
});
}
}
});
});
});
if (singleDocumentReplication) {
var theDoc = theSource[4];
var repFromBase = repFrom.substr(0, repFrom.indexOf(theDoc) - 1);
$.ajax({
url: "/_replicator",
type: "POST",
data: JSON.stringify({ "source": repFromBase, "target": secureHome,
"userCtx": { "name": homeUser, "roles": ["_admin", homeUser] },
"continuous": continuousRep,
"retries_per_request": 10,
"http_connections": 3,
"doc_ids": [theDoc]
}),
contentType: "application/json",
error: function () {
dialog(libLang.noSync);
},
success: function (message) {
if (message) {
dialog(libLang.synced);
}
repTriggered = true;
}
});
} else {
$.ajax({
url: "/_replicator",
type: "POST",
data: JSON.stringify({ "source": repFrom, "target": secureHome,
"userCtx": { "name": homeUser, "roles": ["_admin", homeUser] },
"continuous": continuousRep,
"retries_per_request": 10,
"http_connections": 3
}),
contentType: "application/json",
error: function () {
dialog(libLang.noSync);
},
success: function (message) {
if (message) {
dialog(libLang.synced);
}
repTriggered = true;
}
});
}
}
}
Looks like you've got a ton of code duplication. My recommendation would be to put your ajax calls into modules and pass the $.ajax as a dependency.
So:
function myModule(ajaxDependency, anyOtherDependency) { }
This way in your unit test you simply check to make sure your dependecies behave a certain way. And it looks like it will eliminate all your DRY issues.