Variable conversion in HTML File - YATL

212 views
Skip to first unread message

klaus z

unread,
Dec 23, 2020, 6:10:04 PM12/23/20
to py4web
Within a template/HTML file in py4web i can use the three languages 
- HTML, 
- Javascript and 
- Python3. 
Additionally, for formatting, CSS.

Currently I am having the problem, how to get the Python JSON variable value into a Javascript variable? (It could also be a dataframe or whatever).

Example: 
[[
pyjsondata = [{
    "name": "Paul",
    "age": 31,
    "city": "Ulm"
},
{
    "name": "Otto",
    "age": 23,
    "city": "Friedrichshafen"
}];
]]

[[=pyjsondata]] (to test, thats working, the data is printed)

<script>
jsvarjsondata = pyjsondata (How is this done?)
</script>

htmlvarjsondata = pyjsondata  (How is this done?)

And vice versa, getting the data into a python variable:

[[pyjsondataimpjs = pyjsondata]] (?)

[[pyjsondataimphtml = htmlvarjsondata]]  (?)

Other options could be function calls or storage of data within one language and retrieved from another language. 

Most important seems how to get the data out an into the [[ YATL Python3 Code ]].

Is there somewhere 
- a document (I also looked into web2py manual, but maybe i did not fully understand)?
- Or even better, an example where I can play around? 
(It seems this is py4web and web2py specific).

Jim Steil

unread,
Dec 24, 2020, 10:27:08 AM12/24/20
to py4web
I would guess you would do:

<script>
jsvarjsondata = "[[=pyjsondata]]"
</script>

-Jim

klaus z

unread,
Dec 27, 2020, 5:21:49 AM12/27/20
to py4web
We are on the right way.

With your suggestion Jim, I get (also when asking for the variable on the Javascript console): 

[{&#x27;name&#x27;: &#x27;Paul&#x27;, &#x27;age&#x27;: 31, &#x27;city&#x27;: &#x27;Ulm&#x27;}, {&#x27;name&#x27;: &#x27;Otto&#x27;, &#x27;age&#x27;: 23, &#x27;city&#x27;: &#x27;Friedrichshafen&#x27;}]


Having this code: 

#-*- coding: utf-8 -*- 
# is this uff-8 coding wrong as I have differences between html and js variable, embedded through py4web

[[extend "layout.html"]]

<html>

[[
pyjsondata = [{
    "name": "Paul",
    "age": 31,
    "city": "Ulm"
},
{
    "name": "Otto",
    "age": 23,
    "city": "Friedrichshafen"
}];
]]

<!-- var htmljsonvar = [[=pyjsondata]] // not needed, substituted through: Html Variable: jsonvar -->

<head>
<title>DOM</title>
</head>
<body>
  <p id="one">VARIABLE-Text to be displayed with Javascript in Pop-Up Window </p>
  <p id="jsonvar">[[=pyjsondata]] </p>
  <p> -------------------------- </p>
  <p>This is the welcome message.</p>
  <p>Technology </p>
  <p>This is the technology section.</p>



<script type="text/javascript">

        //demo example, to show principle
var text = document.getElementById("one").innerHTML;
alert("The first heading is: " + text);

        //data got transferred from Python to HTML and them from HTML to Javascript, looks good right now
var jsonscrvar1 = document.getElementById("jsonvar");
alert(jsonscrvar1);

        //data got transferred from Python to HTML and them from HTML to Javascript, looks good right now
var jsonscrvar2 = document.getElementById("jsonvar").innerHTML;
alert(jsonscrvar2);

        //data gets directly transferred from python to Javascript, works in priciple but need to be set correct or tidied through regexp.
var jsonscrvar9 = "[[=pyjsondata]]";
alert(jsonscrvar9);

</script>

</body>
</html>

then (with 'innerHTML'):
jsonscrvar2 looks best: [{'name': 'Paul', 'age': 31, 'city': 'Ulm'}, {'name': 'Otto', 'age': 23, 'city': 'Friedrichshafen'}] 

works best. But on other structure I get the error: 'SyntaxError: Unexpected EOF' (through the Javascript console, see below).

The least necessary code (from you Jim) would be best. But on other structure like a data frame very often I get 

var dfdatajsvar9 = "   x   y
0  A  14
1  B  15
2  C  13
3  D  16
4  E  11
5  F  13
6  G  19
7  H  17
8  I  12"; 

SyntaxError: Unexpected EOF

And the innerHTML command makes:

"{
  \"config\": {
    \"view\": {
      \"continuousHeight\": 300,
      \"continuousWidth\": 400
    }
  },
  \"data\": {
    \"name\": \"data-c29c100fe8b1be6abd3ee935e9c8697d\"
  },

adds backslashes to the promising structure. 

{
  "config": {
    "view": {
      "continuousHeight": 300,
      "continuousWidth": 400
    }
  },
  "data": {
    "name": "data-c29c100fe8b1be6abd3ee935e9c8697d"
  },

Also I had seen this: 

{
  &quot;config&quot;: {
    &quot;view&quot;: {
      &quot;continuousHeight&quot;: 300,
      &quot;continuousWidth&quot;: 400
    }
  },
  &quot;data&quot;: {
    &quot;name&quot;: &quot;data-c29c100fe8b1be6abd3ee935e9c8697d&quot;
  },

Best would be to get rid of the Syntax Error unexpected EOF and use the simple command Jim suggested. Another option would be more coding with innerHTML and them regular expressions to get rid of '&#x27;' or  ‘\‘ and  '&quot;'

Don't spend too much time. But if there is an easy solution (maybe just another character set) or a place where I can investigate further it would help. 

As a side issue, the transfer from [[py4web yatl]] to HTML variables work fine. 

Having py4web/python as the 'common denominator' with simple ways to get HTML or JS variables (maybe other languages) and vice versa would be best. 

I have not investigated jQuery. 

Val K

unread,
Dec 27, 2020, 5:59:45 AM12/27/20
to py4web
It should be 
[[ =XML(json.dumps(pyjsondata)]]
XML() prints string as is

воскресенье, 27 декабря 2020 г. в 13:21:49 UTC+3, klaus...@gmail.com:

Val K

unread,
Dec 27, 2020, 6:48:07 AM12/27/20
to py4web
also you can:
import json

class JSON:
    def __init__(self, d, **opt):
        self.d=d
        opt.setdefault('ensure_ascii', False)
        self.opt=opt
    def xml(self):
        return json.dumps(self.d, **self.opt)

@action('some')
def json_tag_demo():
    json_data = dict(a=1, b=2)
    return dict(json_data = json_data, JSON = JSON) # or you can use inject-fixture 

# template
...
<script>
    var jsvarjsondata = [[=JSON(json_data)]];
</script>




воскресенье, 27 декабря 2020 г. в 13:59:45 UTC+3, Val K:

klaus z

unread,
Jan 2, 2021, 5:57:51 PM1/2/21
to py4web
Thats still open from my side. With both solutions I got slightly data. I tried to avoid to introduce XML as an additional part.
But, the JSON I received was different from what was entered. Instead of:
{
    "name": "Paul",
    "age": 31,
    "city": "Ulm"
}
there were characters like: &quot; or //// or /n in the data. Not even with ReEx operations I got rid of them. And utf-8 coding is unicode and the best.

The better solution was having the data on a weblink and retrieve it from there (similar to retrieving the JSON network data where there was the combination of two tables).

In short:

<body>
<!-- HTML Data/Variables -->
<div id="vis"></div>
<script type="text/javascript">
let url = 'http://127.0.0.1:8004/altair_samp_min/vega_from_altair_unempl_legendsel'; //Unhandled Promise Rejection:
fetch(url)
.then(res => res.json())
.then((out) => {
  console.log('Checkout this JSON! ', out);
})
.catch(err => { throw err });
    vegaEmbed('#vis', url).catch(console.warn);
</script>
</font>
</body>

So I have a Python defined graph (Altair). Converted to JSON Vega Lite code, retrieved from a HTML page (in templates) which is converted D3.js Javascript code. Up to now it seems I can keep the Javascript code and only exchange the link when exchanging the graph.
It even works interactively. And, as Altair/Vegalite still has the original e.g. CSV data links (not the data itself) its flexible.
See attached screenshots.

Maybe later i need to see how to hide/protect the data on the weblink ( http://127.0.0.1:8004/altair_samp_min/vega_from_altair_unempl_legendsel ) thats used to define the graph. For me its a transparent and more easy debug-able solution.

Thanks to both of you for the support.




Bildschirmfoto 2021-01-02 um 23.39.12.png
Bildschirmfoto 2021-01-02 um 23.40.15.png

klaus z

unread,
Jan 4, 2021, 6:02:47 PM1/4/21
to py4web
To avoid misunderstadings, thats closed now. I found a solution.

klaus z

unread,
Apr 12, 2021, 2:40:52 PM4/12/21
to py4web
Let me reopen this thread and change the direction a little. Also I am not sure if I should put the question here. Otherwise let me know

(1) Having a database table where every 120 seconds two records with sensor values get added 

(2) Then I can retrieve the entered data (JSON) when putting an sql statement (polling?) roughly every 120 seconds:
------- controllers.py ----------
@action('YATLsyntax_SCRIPT_graphmax') 
@action.uses('YATLsyntax_SCRIPT_graphmax.html') 
def YATLsyntax_SCRIPT_graphmax():
    rows = dbread((dbread.fritzbox.infolist_detail_name == 'infolist[0][NewMultimeterPower]/100 [W]') 
          & (True)
         ).select(dbread.fritzbox.id, dbread.fritzbox.date_valid,  dbread.fritzbox.infolist_value
                , limitby=(0, 1), orderby=~dbread.fritzbox.id).as_json()
    return dict(rows=rows)
--------

(3) In html with some reformatting I get the data: 
---------- YATLsyntax_SCRIPT_graphmax.html -------
...
</script>

vegaEmbed('#chart64', vlSpec64).then(res =>
    window.setInterval(function () {

        var obj64 = "[[ =rows ]]"
        console.log('initial loaded here the update queue should start - obj64: ',obj64)

        var obj64_1 = obj64.replace(/"/g, '');
        console.log('removed " obj64_1: ',obj64_1)

        var obj64_2 = JSON.parse(obj64_1.replace(/&quot;/g,'"'));
        console.log('replaced quot, should be graph data obj64_2:',obj64_2)

        var obj64_3 = obj64_2;
        console.log('replaced quot, should be graph data obj64_3:',obj64_3)
        for (i = 0; i < obj64_3.length; i++) {
            var obj64_4 = obj64_3[i];
            res.view.insert('table64', obj64_4)
            .run()
        }
    }, 120000) //Delay or total Graph. Should be above, stepwise
);

</script>

[[ =rows ]]

---------

Even having a window.setInterval(function () { ....    }, 120000) every 2 minutes (120,000ms) there is 
- no update of the YATL html field: [[ =rows ]]

Also there is no update of the Javascript field: 
- var obj64 = "[[ =rows ]]"


Both fields get updated initially when the page is loaded. But there is no cyclical update of the YATL field itself, what was expected to happen every 120 seconds (afterwards). 

Don't spend much time. But any hint what i could try is welcome.

~Klaus 

Jim Steil

unread,
Apr 12, 2021, 3:18:37 PM4/12/21
to py4web
Klaus

I'm not positive I'm understanding this correctly, but rows is only going to get a new value when you reload the page

[[=rows]] is only evaluated once, when the page is being built.  To poll for new records on the server I'd use a javascript fetch to gather the new data within your setInterval

-Jim

klaus z

unread,
Apr 13, 2021, 12:00:30 PM4/13/21
to py4web
Thank you Jim. 

Even it took me some time now but your guidance saved me more than a few hours and now there is the proof that it is working. Fetching i had used but for a different purpose

With the DAL statement in DAL i have to be careful with the code. Initially i had backslashes etc where i unsuccessfully tried to get rid with RegExp until i found this more clean statement.  

--- controllers.py --- 
@action('YATLsyntax_SCRIPT_graphmaxlinkjson') 
def YATLsyntax_SCRIPT_graphmaxlinkjson():
    logdata = dbread(dbread.fritzbox.infolist_detail_name == 'infolist[0][NewMultimeterPower]/100 [W]'
         ).select(dbread.fritzbox.id, dbread.fritzbox.date_valid,  dbread.fritzbox.infolist_value
                , limitby=(0, 1), orderby=~dbread.fritzbox.id).as_list()
    return dict(logdata=logdata)
-----

and 


{
 "logdata": [ 
 {
 "date_valid": "2021-04-13T17:50:12",
 "id": 25287,
 "infolist_value": 183.67 
 } 
 ] 
}

-----

and 

----- YATLsyntax_SCRIPT_graphmax.html ----
vegaEmbed('#chart64', vlSpec64).then(res =>
    window.setInterval(function () {

        var d = new Date();
        var t = d.toLocaleTimeString();

        var obj64 = []
        console.log(t ,' - initial loaded Empty obj64: ',obj64)

        fetch(url)
        .then(res => res.json())
        .then((obj64) => {
        console.log('Fetch JSON received! ', obj64); 
        console.log(' - - -  after initial loaded, now data from SQL - obj64: ',obj64)

        var obj64_3 = obj64.logdata;
        console.log('Values obj64_3: ',obj64_3) 

        for (i = 0; i < obj64_3.length; i++) {
            var obj64_4 = obj64_3[i];
            res.view.insert('table64', obj64_4)
            .run()
        }

        })
        .catch(err => { throw err });

    }, 120000) //Delay or total Graph. Should be above, stepwise
);

</script>

[[ =rows ]]
---

Well, its not YATL anymore. Also i need to tidy up as it is now nearly 6 pm and not 8pm. 2021 and not 2012. Minor issues. 
And the application should get a better name (without yatl).

For now getting old date into the graph and synchronization is a minor  issue. Sooner or later I should be able to activate the entries from a trigger when new data is entered into the db-table.  

~Klaus

Bildschirmfoto 2021-04-13 um 17.46.54.png
Reply all
Reply to author
Forward
0 new messages