In the Row_Rendered section (table-specific->common) I included some jquery via tag. (v2020)
This script makes it possible for users to change a value in one specific column (in list view) which is immediately (when field focus is lost) updated in the database via Ajax.
But this gives error in the code inspector: Uncaught reference error: $ is not defined (referring to the line $(document).ready.)
I could walk around this error by adding some js-includes in Global->Page Head.
This works OK in Google Chrome, Safari, Edge, but gives issues in Firefox, Internet Explorer…Question is whether above approach is OK, or how else should I handle this?
You should not output JavaScript in Row_Rendered server event. In List page this event will be fired as many times as the number of records per page, and the server event is not a suitable location to output HTML. You should use client side Client Script or Startup Script, read Client Scripts. Also, you should not include the scripts again in Page_Head.
OK, basic issue is the following:
I have some jqeury code in table-specific->Row_Rendered (see jquery code below).
Don’t worry about the code itself. It works fine.
The reason why I need this code in Row_rendered is because it must be executed for every row. It provides some functions to the user to update a field immediately in list view (updated in db via ajax). It also changes the field color dynamically depending on the field content and other fields in the same record.When the application runs, the browser throws an error saying:
Uncaught ReferenceError: $ is not definedAfter some research I learned this seems to be the case when jquery code is executed before the jquery module is downloaded. Although I see that jquery is already included in header.php:loadjs(“<?php echo $RELATIVE_PATH ?>jquery/jquery-3.4.1.min.js”, “jquery”);So that’s strange… Has maybe something to do with asynchroneously loading? So what comes first: $(document).ready() or loadjs?To work around this problem, I included the jquery-module manually in List page->Page Load:echo “”;And strangely enough: this works perfect… in Google Chrome (and Edge and Safari), but not in Firefox or Internet Explorer.
First time when you run in these browsers, you get spinning wheel. After refresh page, it works (as if something is loaded in cache after refresh).
Any idea what could be wrong?
As suggested, you better use client side events, e.g. in Startup Script
loadjs.ready("head", function() {
// your code
});
I’m not sure what elements (“#mronde_” . $this->id->CurrentValue) in your code are. If they are created by yourself, you can add a class to your elements, so you can select them all by class so you do not need to use Row_Rendered server event, e.g. in Startup Script
$("[id^=mronde_]").on("change", function(e) { // Select all elements with id starting with "mronde_" or if you have added your class to your elements you may use $(".my-class")
// your code
});
I’m not sure what elements (“#mronde_” . $this->id->CurrentValue) in your code are
Indeed, I forgot little piece of code (right below the jquery code) which determines the field-id:
if(CurrentPageID() == "list" && $this->datum2->CurrentValue == ""){
$this->ronde->ViewValue = "<input type = text
id = 'mronde_".$this->id->CurrentValue."' maxlength='1' size='2' value='".$this->ronde->CurrentValue."'>";
}
But anyway, your advise to use loadjs.ready (in stead of document.ready) works perfect!So I could remove the line echo “” from the place where it does not belong.
As explained, a loadjs script is included in row_rendered as it needs to be executed for every row.And that works perfect… for the first 25 rows or so. When I go deeper into the list, the script doesn’t work anymore.
During the load of the page, the ajax-code is not fired. It’s only executed after the on-change-event as you can see in the code earlier.When I enter something in the field “ronde” in the upper rows, than the ajax is called ok (including some re-styling of that field via jquery).But when I scroll down the list (20 records or more further) and make update similar update to “ronde” the script-code is not executed (the ajax+restyling) although when you look in the html-code of the page, the script-code for that record is in there.I also performed network analysis (but I’m novice to that) and couldn’t find direct explanation.
Since the HTML that you are working with is generated by your own code, you better post the outputted HTML of the problem row and your JavaScript in Startup Script (Right click the element in Chrome and select Inspect and go to the Elements panel to copy outputted HTML, see Open the Elements panel to inspect the DOM or CSS) for discussion.Press F12 in your browser and go to the Console panel, test your script, when it does not work, check for JavaScript errors in the Console panel.To check if your Ajax is working properly, see Check HTTP Response.Note again that your Startup Script should be like: (The CSS selector is “[id^=mronde_]”)
$("[id^=mronde_]").on("change", function(e) { // Select all elements with id starting with "mronde_" or if you have added your class to your elements you may use $(".my-class")
// your code
});
The outputted html looks exactly the same (except for the row-id and some inputted content) for working lines as for non-working lines. See HTML-extract below.
There is no javascript error and there is no ajax-error for the simple reason that the on(‘change’)-event at the beginning of the script doesn’t seem to trigger when it should.
I changed the syntax as you indicated, but it doesn’t make any difference.
Something I noticed yesterday is that this strange behaviour is only in Chrome and Edge. Firefox and Safari are working perfect, meaning you can edit the field “ronde” even in the 100th line.Maybe it will help when I try to create a function call within the script to avoid having all those duplicate script lines?HTML-extract (note, page has about 13000 lines when 100 records are displayed):
=========================================================================
Code for non-working line (97th record - ID = 27409) (177 lines) :
(1 extra line is just because of some more inputted data in a text-field)
=========================================================================
<script>
loadjs.ready('head', function () {
//$('#mronde_27409').on('change', function(e) {
$('[id^=mronde_27409]').on('change', function (e) {
//e.preventDefault;
allowedRonde = 'BJMS'; //Allowed characters
nieuweRonde = $(this).val().toUpperCase(); //convert to uppercase
interventieId = 27409;
//alert(nieuweRonde); //debug
//alert(interventieId); //debug
if (allowedRonde.search(nieuweRonde) < 0) { //check if entered value allowed
ew.alert('Fout ronde:<BR>Enkel B, J, M of S toegestaan'); // error if not.
$(this).closest('td').css('background-color', 'red');//make background red
} else { //proceed if allowed
$.ajax({ //ajax request to update ronde //ajax request
url: 'PMupdateRonde.php',
data: { id: interventieId, ronde: nieuweRonde },
type: 'POST',
success: function (result, status, xhr) {
//alert(result);//debug
$('#rondeTeller').html(result); //put the result of the dashboard in the
//div-element with id = rondeTeller
$('.dashboard_r').css({ 'background-color': 'red' }); //change background of assignee counters to red
$('.dashboard_r').click(function () { //as addresses are not updated, set warning message
ew.alert('Ververs pagina om adressen te zien.');
});
},
error: function (xhr, status, error) {
alert(error);
}
});
if (nieuweRonde) { //color blue when changed to other value
//alert('ronde ingevuld');//debug
$(this).closest('td').css('background-color', '#9999FF');
} else { //color lightred when emtied
//alert('ronde leeggemaakt');//debug
$(this).closest('td').css('background-color', '#FF9999');
}
}
})
//})
})
</script>
<tr data-rowindex="97" id="r97_meldingen_admin" data-rowtype="1">
...
<td data-name="ronde" style="background-color:#FFDDDD;white-space: nowrap;">
<span id="el97_meldingen_admin_ronde">
<span><input type=text id='mronde_27409' maxlength='1' size='2' value=''></span>
</span>
</td>
...
</tr>
you do > not need to use Row_Rendered server event> , e.g. in > Startup Script
$(“[id^=mronde_]”).on(“change”, function(e) { // Select all elements with id starting with “mronde_”…
The selector is “[id^=mronde_]”, not “[id^=mronde_xxx]”. Read Attribute selectors. The selector is not to replace “#mronde_xxx”, but to select all elements with id=mronde_xxx in Startup Script once only.
If you must use your own approach, you should change loadjs.ready(‘head’, …) to loadjs.ready(‘load’, …). If you use ‘head’, when you have a lot of records, your JavaScript code (outputted before the HTML) may be fired before the HTML is rendered by the browser.Other issues in your code:
Use var or preferrably let in your JavaScript, do not set a variable like allowedRonde = ‘BJMS’; only.
Do not repeatedly add $(‘.dashboard_r’).click(…) to the same element(s).
Thanks a lot!The “load” vs “head” parameter in the loadjs-instruction did it (keeping my approach).
Everything works smooth now in all browsers :-)I’ll review my code based on your recommendations!Kind regards!