Works fine in JSFiddle but locally


#1

The following JSFiddle works fine without any errors. I am trying to run it locally on my browser and I keep on getting following error :

What am I doing wrong? Here is the code I am using locally :

<html>
<head>
  <script type="text/javascript" src="https://jqwidgets.com/public/jqwidgets/jqx-all.js"></script>
  <link rel="stylesheet" href="https://jqwidgets.com/public/jqwidgets/styles/jqx.base.css">
  
</head>
<body>
<div id="grid"></div>
<script type="text/javascript">
     var source =
                {
                    localdata: [
                        ["https://www.samplelink.com", "Maria Anders", "Sales Representative", "Obere Str. 57", "Berlin", "Germany"],
                        ["https://www.samplelink.com", "Ana Trujillo", "Owner", "Avda. de la Constitucin 2222", "Mxico D.F.", "Mexico"],
                        ["https://www.samplelink.com", "Antonio Moreno", "Owner", "Mataderos 2312", "Mxico D.F.", "Mexico"],
                        ["https://www.samplelink.com", "Thomas Hardy", "Sales Representative", "120 Hanover Sq.", "London", "UK"],
                        ["https://www.samplelink.com", "Christina Berglund", "Order Administrator", "Berguvsvgen 8", "Lule", "Sweden"],
                        ["https://www.samplelink.com", "Hanna Moos", "Sales Representative", "Forsterstr. 57", "Mannheim", "Germany"],
                        ["https://www.samplelink.com", "Frdrique Citeaux", "Marketing Manager", "24, place Klber", "Strasbourg", "France"],
                        ["https://www.samplelink.com", "Martn Sommer", "Owner", "C\/ Araquil, 67", "Madrid", "Spain"],
                        ["https://www.samplelink.com", "Laurence Lebihan", "Owner", "12, rue des Bouchers", "Marseille", "France"],
                        ["https://www.samplelink.com", "Elizabeth Lincoln", "Accounting Manager", "23 Tsawassen Blvd.", "Tsawassen", "Canada"],
                        ["https://www.samplelink.com", "Victoria Ashworth", "Sales Representative", "Fauntleroy Circus", "London", "UK"],
                        ["https://www.samplelink.com", "Patricio Simpson", "Sales Agent", "Cerrito 333", "Buenos Aires", "Argentina"],
                        ["https://www.samplelink.com", "Francisco Chang", "Marketing Manager", "Sierras de Granada 9993", "Mxico D.F.", "Mexico"],
                        ["https://www.samplelink.com", "Yang Wang", "Owner", "Hauptstr. 29", "Bern", "Switzerland"],
                        ["https://www.samplelink.com", "Pedro Afonso", "Sales Associate", "Av. dos Lusadas, 23", "Sao Paulo", "Brazil"],
                        ["https://www.samplelink.com", "Elizabeth Brown", "Sales Representative", "Berkeley Gardens 12 Brewery", "London", "UK"],
                        ["https://www.samplelink.com", "Sven Ottlieb", "Order Administrator", "Walserweg 21", "Aachen", "Germany"],
                        ["https://www.samplelink.com", "Janine Labrune", "Owner", "67, rue des Cinquante Otages", "Nantes", "France"],
                        ["https://www.samplelink.com", "Ann Devon", "Sales Agent", "35 King George", "London", "UK"],
                        ["https://www.samplelink.com", "Roland Mendel", "Sales Manager", "Kirchgasse 6", "Graz", "Austria"]
                    ],
                    datafields: [
                        { name: 'link', type: 'string', map: '0' },
                        { name: 'ContactName', type: 'string', map: '1' },
                        { name: 'Title', type: 'string', map: '2' },
                        { name: 'Address', type: 'string', map: '3' },
                        { name: 'City', type: 'string', map: '4' },
                        { name: 'Country', type: 'string', map: '5' }
                    ],
                    datatype: "array"
                };
            var dataAdapter = new $.jqx.dataAdapter(source);

            var cellsrenderer = function (row, column, value) {
                return `<div style="color: blue">${value}</div>`;
            };

            $("#grid").jqxGrid(
                {
                    width: 800,
                    source: dataAdapter,
                    columnsresize: true,
                    sortable: true,
                    columns: [
                        { text: 'Link', datafield: 'link', width: 200, cellsrenderer: cellsrenderer },
                        { text: 'Contact Name', datafield: 'ContactName', width: 150 },
                        { text: 'Contact Title', datafield: 'Title', width: 100 },
                        { text: 'Address', datafield: 'Address', width: 100 },
                        { text: 'City', datafield: 'City', width: 100 },
                        { text: 'Country', datafield: 'Country' }
                    ]
                });

            var id = 1;

            $("#grid").on("rowselect", function (e) {

                $("<div />")
                    .append($("<div />", { id: "grid" + id }))
                    .append($("<div />", { id: "button" + id }))
                    .appendTo(document.body);
               

                $("#grid" + id).jqxGrid({
                    source: dataAdapter, columns: [
                        { text: 'Link', datafield: 'link', width: 200, cellsrenderer: cellsrenderer },
                        { text: 'Contact Name', datafield: 'ContactName', width: 150 },
                        { text: 'Contact Title', datafield: 'Title', width: 100 },
                        { text: 'Address', datafield: 'Address', width: 100 },
                        { text: 'City', datafield: 'City', width: 100 },
                        { text: 'Country', datafield: 'Country' }
                    ]
                });

                $("#grid" + id).on('rowselect', function () {
                    $("<div />")
                        .append($("<div />", { id: "grid" + id }))
                        .append($("<div />", { id: "button" + id }))
                        .appendTo(document.body);


                    $("#grid" + id).jqxGrid({
                        source: dataAdapter, columns: [
                            { text: 'Link', datafield: 'link', width: 200, cellsrenderer: cellsrenderer },
                            { text: 'Contact Name', datafield: 'ContactName', width: 150 },
                            { text: 'Contact Title', datafield: 'Title', width: 100 },
                            { text: 'Address', datafield: 'Address', width: 100 },
                            { text: 'City', datafield: 'City', width: 100 },
                            { text: 'Country', datafield: 'Country' }
                        ]
                    });

                    $("#grid" + id).on('rowselect', function () {

                    });

                    $("#button" + id).jqxButton({ value: 'Export Grid ' + id });

                    let currentId = id;
                    $("#button" + currentId).on('click', function () {
                        //console.log('clickin ', currentId)
                        $("#grid" + currentId).jqxGrid('exportdata', 'pdf', 'jqxGrid' + currentId);
                    });

                    id++;
                });

                $("#button" + id).jqxButton({ value: 'Export Grid ' + id });

                let currentId = id;
                $("#button" + currentId).on('click', function () {
                    //console.log('click ', currentId)
                    $("#grid" + currentId).jqxGrid('exportdata', 'pdf', 'jqxGrid' + currentId);
                });

                id++;
            });
            

</script>
</body>
</html>

#2

This is very curious. It works when you wrap your code in an IIFE (as jsfiddle by default wraps your code in an onload function), or when you rename your id variable to something else… so it almost seems as if jqx also attempts to declare / access an id variable in the global scope*. :-O I’m not familiar with jqx though, so I don’t know if this behaviour is on purpose, or if I’m missing something here.

PS:
*) … or maybe it sets an .id property on the window object, which also maps to variables declared in the global scope with var and vice versa. Anyway I guess the takeaway is: never declare variables in the global scope.


#3

My guess is it has something to do with synchronization. The code that creates the (closing?) div with the id value “button + id” comes before the line of code that references the id, but that may not mean the code is running in that sequence.

If that is the problem I don’t know what might be the better way to deal with. Both chaining and conditional loops give me a “it could get messy” feeling.


#5

Hey @Mittineague, no it has nothing to do with the sequence of function calls in the code – see my above reply. But I can confirm now that there are several attempts to set a window.id property; if you place the following snippet at the top of the code, you can see undefined getting logged 20 times (presumably once for each localdata entry):

Object.defineProperty(window, 'id', {
  set: console.log
})

#6

So you would recommend to declare the variable as let id instead of var id ?


#7

Well as you’re already using let elsewhere anyway there’s no need to ever use var really. But you should nevertheless wrap your code in an IIFE to create your own scope and avoid conflicts with other code:

(function () {
  // Your code goes here
})()