Usually Angular get from HTTP request the JSON from server side (like Django).
But, to accelerate rendering, would like to write down on server side the JSON into a Javascript VAR and let proceed Angular on this javascript variable containing the JSON.
My question are:
1) How to pass this javascript var to angular $scope variable ?
(without HTTP).
2) Is writing down the JSON into the HTML a bad/good practice ?
(given my web app is fairly static).
You can do a simple $scope = {{ some_django_tag|safe }}. I can't see why it would be a bad practice if you're 100% sure that the output will be valid JS. I actually do this a bit to instantiate the scope on the page load.
Related
I have researched how to send data from Rails to JavaScript in a Slim view template, and the most accepted method is to declare a Ruby section on the Slim template to get the data from the controller, and then declare a JavaScript section to store that data into a window variable, and then load the JavaScript pack that's going to use that data.
The data is needed to build a JavaScript snippet that will go in the <head> of our app.
Here's an example of what I'm doing (this is the app/views/layouts/_my-template.html.slim file):
ruby:
myDataFromRails = #my_data.to_json.html_safe
javascript:
window.myData = #{myDataFromRails};
- include_javascript_pack 'my-pack'
The problem with this method is that all the data coming from the Rails backend is available for anyone that inspects the code or types window.myData in the developer tools console, which is not ideal...
Another option will be to query the backend from the JavaScript snippet itself, using an HTTP request, but this doesn't look like an efficient way of getting the data from the backend.
I'm using Spring Boot with Thymeleaf, and know I can use variables from my controller on the following way in javascript:
<script th:inline="javascript">
/*<![CDATA[*/
var username = [[${#authentication.principal.person.isSubscribedTo("random string")}]];
/*]]>*/
</script>
Now I tried to use a local variable outside the CDATA comment like this. I expected I could use that in the method.
var randomString = "can i use this?";
/*<![CDATA[*/
var username = [[${#authentication.principal.person.isSubscribedTo(randomString)}]];
/*]]>*/
This does not work and I can't test this because my debugger won't get it the method and is not giving back any errors.
How can I use a local javascript variable in a thymeleaf javascript expression?
You're showing a bit of confusion about what's happening when and where.
First, the server uses Thymeleaf to generate the HTML and dynamic Javascript for a page. In this process, as you've said Thymeleaf can call into your Spring beans as it's running on the server.
Then, once the HTML & dynamic Javascript is sent to the browser, it runs the Javascript all client-side.
The only real approaches are:
Generate that randomString on the server side as well, within Thymeleaf or in the model accessible to Thymeleaf.
If you need to generate that string on the client side, have the Javascript make a separate HTTP request ("AJAX") call with that information to the server, and then do something reasonable with the response. That is to say, once the Javascript is sent to the browser, if you need to make more round trips to the server it's on the Javascript to ensure that it happens, as Thymeleaf's role in the page is done.
I know we can set Jinja variable to js variable like this.
var x = {{ 'value' }}
but I am trying to do the reverse. i.e I am trying to set javascript value to jinja variable. I tried the following but nothing worked.
{{value}} = x
{% set value = x %}
{% set value %} x {% endset %}
x is javascript variable.
is there any way to achieve this.
This is not possible, and reflects a deep problem in your understanding of the web application architecture. jinja2 is a templating engine for Python, running on your server. JavaScript you are talking about is running in your browser.
When a server receives a request, it processes a jinja2 template to obtain the response it will send to the client. You cannot "set Jinja variable to js variable", you can render the page in such a way that eventually a JavaScript variable would be assigned a value that was in a Jinja2 variable. I.e. you start with var x = {{ value }} in jinja2 template; jinja2 transforms it into var x = 42 during its rendering; then the rendered result gets sent to the client, which executes it as JavaScript, assigning a value 42 to x. The fact that there is a temporal sequence here (Python -> jinja2 -> rendered page source -> JavaScript) means you can't do what you want to do: The jinja2 variable and the JavaScript variable don't exist at the same time, nor in the same place, and assigning a JavaScript value to a jinja2 variable is impossible.
In order to send the value 42 to Python (and possibly later to jinja2), you would need to make a request that would send that value from client to server: a form submission, or an AJAX request.
You might get a better response if you would describe exactly what you want to do that you think requires you to "set javascript value to jinja variable".
This is an old thread and the answer might still be "it cannot be done" but I would like to point out a mistake in both the answers above. The Question is "How to set javascript value to jinja variable". What He is asking is if you have JavaScript running on your front end page that needs a certain value to work and that value is given by the backend script and passed in via Jinja2 can you make that work? (AJAX perhaps).. Both "Answers" above while detailed and informative don't address this question. They both seem to address the opposite question, "Can you set a jinja2 variable from a javascript" which I agree does not make sense.
I'm looking for the answer to the same question (How to set javascript value to jinja variable) because This tutorial on flask with charts shows you inserting a jinja variable into a java script. The problem is Java looks at the double bracket ( {{ VAR1 }} )as part of the script and throws errors.
The way you're describing, it can't be done.
Let's review Python, Jinja2, and JavaScript, because I think we can still achieve what you want.
Python is the language of your server, which will create the HTML sent to your clients.
Jinja2 is a templating engine for Python, which makes it easy to generate HTML without writing it directly. Notice that you're calling a function like render_template() in your backend. This generates the HTML using Jinja2 syntax, replacing Jinja2 statements with values known to the server, and inserting them into the HTML before it gets presented to the client. Think of Jinja2 as shorthand for variable insertion and simple scripting for making HTML.
JavaScript is your frontend scripting language, running on the client's browser once the HTML has been generated and served.
The reason you can't use Javascript to "set a Jinja2 variable" is because there are no Jinja2 variables in the rendered HTML sent to the client. Python and Jinja2 did that replacement on the server before sending the pure HTML/CSS/JS page to the client's browser.
Perhaps what you want to do though, is use frontend elements to change values that were initially set by python and Jinja2 on the backend. To do this, you will need to have your JavaScript send information back to the server, so the server can use this information to rerender the page, possibly inserting new values into your templates using Jinja2 in the process. Consider simply linking to a URL with the parameter you want to set.
You could link to www.yourwebsite.com?x=value, and now x will be set to 'value' in the backend. You can use this in your HTML template by including {{ x }}, which will resolve to 'value' when you call render_template()
Well... you could send a post request from your javascript to the server and then from your python backend send the information to the html frontend
javascript frontend > POST > python backend > TEMPLATE > html frontend
I have a fairly large Application and I'm currently trying to find a way around having to pass Data from PHP (User Tokens for 3rd Party API's and such) through the DOM. Currently I use data-* attributes on a single element and parse the Data from that, but it's pretty messy.
I've considered just making the contents of the element encoded JSON with all the config in, which would greatly improve the structure and effectiveness, but at the same time storing sensitive information in the DOM isn't ideal or secure whatsoever.
Getting the data via AJAX is also not so feasible, as the Application requires this information all the time, on any page - so running an AJAX request on every page load before allowing user input or control will be a pain for users and add load to my server.
Something I've considered is having an initial request for information, storing it in the Cache/localStorage along with a checksum of the data, and include the checksum for the up-to-date data in the DOM. So on every page load it'll compare the checksums and if they are different (JavaScript has out-of-date data stored in Cache/localStorage), it'll send another request.
I'd rather not have to go down this route, and I'd like to know if there are any better methods that you can think of. I can't find any alternative methods in other questions/Google, so any help is appreciated.
You could also create a php file and put the header as type javascript. Request this file as a normal javascript file. <script src="config.js.php"></script> (considering the filename is config.js.php) You can structure your javascript code and simply assign values dynamically.
For security, especially if login is required, this file can only be returned once the user is logged in or something. Otherwise you simply return a blank file.
You could also just emit the json you need in your template and assign it to a javascript global.
This would be especially easy if you were using a templating system that supports inheritance like twig. You could then do something like this in the base template for your application:
<script>
MyApp = {};
MyApp.cfg = {{cfg | tojson | safe}};
</script>
where cfg is a php dictionary in the templating context. Those filters aren't twig specific, but there to give you an idea.
It wouldn't be safe if you were storing sensitive information, but it would be easier than storing the info in local storage,
I am building a internal web app with Flask that connects to various clusters. 95% of the URLs start with /cluster/cluster_name so I use the following code in my blueprints:
cluster = Blueprint('cluster', __name__, url_prefix='/cluster/<cluster_name>')
#cluster.url_defaults
def add_cluster_name(endpoint, values):
values.setdefault('cluster_name', g.cluster_name)
#cluster.url_value_preprocessor
def pull_cluster_name(endpoint, values):
g.cluster_name = values.pop('cluster_name')
Which then allows me to use the following code to create a connection to the cluster before each request:
#app.before_request
def before_request():
if not hasattr(g, 'manager'):
g.manager = ClusterInterface(g.cluster_name)
This works perfectly and allows me to use {{ g.cluster_name }} in jinja2 templates.
The problem is that I am moving to an AngularJS app for the frontend so I won't be using jinja2 templates/render_template() anymore.
So how can I have this global available to AngularJS templates without returning its value from every Flask views?
Thank you.
Your views will now send JSON data instead of rendered HTML templates in order to communicate with Angular. So make this data available in the JSON response.
return jsonify(cluster_name=g.cluster_name)
More likely, you should just send the default and available names when you first start the Angular app, and let it handle the value on it's end.
Sending g.manager is impossible, since it's a Python object with (probably) complex behavior, not something that is JSON serializable.