Best way to pass server (c# / Razor) values into an AngularJS app - javascript

We use DNN and often need to pass a few context specific values (like page id or module-on-page-id) into an AngularJS app. We've developed our own conventions how to do this, but would like to hear from others how they approach this to find a best practice.
So basically the situation is that the server-page has information needed by the JS. Using WebAPI is not an option, as these values are known in the page, but not in a separate request. Things I've seen so far have been:
Use in-view-razor like href="#Tab.TabId/{{...}}" (I don't like this)
Place the values in the ng-init like ng-init="config = { prop1: '#Tab.TabId' }"
Create a separate <script> tag where we generate a module on the fly containing these values so angular.module("config", []).constant('prop1', '#Tab.TabId')
Create a json with razor in the page somewhere and inject all of it as a module into the app using a generic code which does the same as #3, just with cleaner code re-use.
I've seen all these and have also used all. Currently we avoid #1 as we believe it's not good to mix templating languages and because it doesn't allow externalizing parts of the view. So basically we use #2 as for quick-and-simple (and a bit dirty) + #3/#4 for larger projects.
Do you have a better way, or which way would you prefer?

We are using variant #4.
This has the advantage that the JSON defines the exact interface for the config needed by the JS module. And Razor is great to generate URLs using #Url.Action.

we use NewtonSoft and do JSONConvert.SerializeObject(ObjectName) and then pass it over as a Session from the controller and then use #Html.Raw(ObjectName) and its a JSON Object that can be utilized easily in javascript...

Related

Best way to use C#-Ressources (ResX Files) in Typescript?

our current project is in ASP.Net MVC with Razor.
We use ResX Files for a few thousend translations.
In C# and Asp.net Razor this is pretty easy with HTML:
<div>#Ressources.Local.Test</div>
Now when I wrote JavaScript I normaly did this within the cshtml files with razor like this:
<script>alert('#Ressources.Local.Test');</script>
Which works but seems a bit ugly...
A few weeks ago we starded with Typescript, and, of course excluding (nearly) all javascript code to ts-files.
The only solution we found here, to get the ressources from C# to Typescript is through a "hack":
We made a ressources.cshtml file in which we just include javascript variables:
var ressourceTest = "#Ressource.Local.Test";
We load this ressource.cshtml at first in our _layout.cshtml.
Additional, we have a self need a selfmade declarion for this variable to jump from javascript to typescript in our projectDeclarions.d.ts:
var ressourceTest:string;
And now we can use the ressource in our typescript file test.ts:
alert(ressourceTest);
As you can see it is a working "hack" or "workaround" but it seems to likly kill us for a few thousend ressources... It's handmade, the maintain duration and work is high...
Any better ideas?
I have seen a few good ideas around this.
You could supply an JSON endpoint in your MVC application to give you chunks of translations. You would decide how granular you want to make it, but you would essentially JSON serialize a translation, or set of translations and send it back. This would avoid stuffing a big view with hundreds of the things.
Another alternative is to place translations in the view to make them available, but contextually. So if you had a button that you are using to trigger some AJAX call to the server and you need to say "Update Worked" or "Update Failed" you could put the attributes inline...
<button ... data-msg-success="Saved OK" data-msg-failed="A problem occurred" />
And you could populate these attributes with your resources.

Passing a JSON object to a remote LESS compiler to use as LESS variables

I have an admin panel where users customize the look of a static website (mostly fonts and colors). This panel generate a JSON object with the user values. What I would need to do is passing this JSON to the LESS compiler, so that it can dynamically generate a CSS file from a LESS one using the JSON content as LESS variables. The filename should be different every time, something line file-ID.css (the ID is for the user and it could be passed via JSON too).
Is it technically possible (without extending LESS)? I noticed, for example, that you can pass functions to the parser object when you create it, could I use this functions to evaluate the JSON and passing the variables to the compiler?
Obviously I don't need to know the details, just if it is doable and possibly some link to related information if you have it.
Thanks in advance.
The best way I've found to do what I was trying to accomplish was to use a server side LESS library like PHPLESS to parse the variables from the JSON before compiling. Regular LESS compiler doesn't allow to dynamically inject variables.
To my knowledge the LESS compiler doesn't support any other input than LESS. It would be trivial to make your own pre-parser that mixes-in the variables from JSON .. not even a parser, more of a string-replacer.

Passing data from my razor view to my js file

I'm searching for the best way to pass data from my razor view to my js file. For example, lets say we have a jquery dialog configured in the js file. For buttons text on this dialog, I would like to localize it (through resource files FR/NL/UK). The translations are available with #UserResource.ButtonDelete + #UserResource.ButtonCancel
Below are the different solutions I see:
Using the nice RazorJS nuget package to allows razor code inside my javascript file. It works pretty well. But the question is: is it a bad practice to compile js files in order to use razor syntax inside the scripts?
Declaring global variables in the js script file and assign value from the view like this:
In the view:
<script>
var labelButtonDelete = #UserResource.ButtonDelete;
</script>
In the js file:
alert('The text for my button is ' + labelButtonDelete);
What is the best way to pass data from razor to js file? Do you have another alternative?
Thanks anyway.
I've been using something like your second approach for some time without any issues. The only difference is that I'm using a singleton in my JS file to avoid polluting the global javascript namespace.
But if you will be doing more serious client side stuff, your Javascript code will follow a more object oriented structure, and from there you almost automatically get a single initialization/constructor path where you can pass your localized values.
That RazorJS looks nice, but I'm not sure if I'm comfortable mixing Javascript with Razor. Might do it for a small project, but I can see it becoming really messy if you have lots of Javascript files.
After all, I still consider the resources/localization code to be related to the view. The Javascript should only implement functionality in my opinion.

Client side templating with unknown variables

Our company has an intranet consisting of several e-mail templates filled with variables (like [[NAME]], [[PROJECT]] and so on). I was thinking of implementing some sort of client side templating to make it easier to replace these variables with actual values.
The problem is that among all the client side template solutions I've located so far, all of them seem to assume that the JS code knows all the template variables that exist in the markup, and none of them seem to be able to fetch a list of variables defined in the markup.
Does anyone know of any solutions/plugin which makes this possible?
Thanks in advance!
Can't you just use some simple regex?
var variables = mycontent.match(/\[\[(.*?)\]\]/g);
I set up a demo here, so you can see it in action.
If set of templates are already cached on client and available to customer on demand and each template will have it own set of information to be replaced in (either hardcoded or define on runtime). Then we can go for some generic solution
Pseudo code
- Decide which Template now need to render
- Send a Ajax command of array of variables in to be replace in the template
[{var_name:"%project_name%",var_value:"Project" },{var_name:"%superviser%",var_value:"Its me :)" }]
- Write a generic code that loop through json array and replace the var_name with the template source
Check this - http://api.prototypejs.org/language/template/

Passing Python Data to JavaScript via Django

I'm using Django and Apache to serve webpages. My JavaScript code currently includes a data object with values to be displayed in various HTML widgets based on the user's selection from a menu of choices. I want to derive these data from a Python dictionary. I think I know how to embed the JavaScript code in the HTML, but how do I embed the data object in that script (on the fly) so the script's functions can use it?
Put another way, I want to create a JavaScript object or array from a Python dictionary, then insert that object into the JavaScript code, and then insert that JavaScript code into the HTML.
I suppose this structure (e.g., data embedded in variables in the JavaScript code) is suboptimal, but as a newbie I don't know the alternatives. I've seen write-ups of Django serialization functions, but these don't help me until I can get the data into my JavaScript code in the first place.
I'm not (yet) using a JavaScript library like jQuery.
n.b. see 2018 update at the bottom
I recommend against putting much JavaScript in your Django templates - it tends to be hard to write and debug, particularly as your project expands. Instead, try writing all of your JavaScript in a separate script file which your template loads and simply including just a JSON data object in the template. This allows you to do things like run your entire JavaScript app through something like JSLint, minify it, etc. and you can test it with a static HTML file without any dependencies on your Django app. Using a library like simplejson also saves you the time spent writing tedious serialization code.
If you aren't assuming that you're building an AJAX app this might simply be done like this:
In the view:
from django.utils import simplejson
def view(request, …):
js_data = simplejson.dumps(my_dict)
…
render_template_to_response("my_template.html", {"my_data": js_data, …})
In the template:
<script type="text/javascript">
data_from_django = {{ my_data }};
widget.init(data_from_django);
</script>
Note that the type of data matters: if my_data is a simple number or a string from a controlled source which doesn't contain HTML, such as a formatted date, no special handling is required. If it's possible to have untrusted data provided by a user you will need to sanitize it using something like the escape or escapejs filters and ensure that your JavaScript handles the data safely to avoid cross-site scripting attacks.
As far as dates go, you might also want to think about how you pass dates around. I've almost always found it easiest to pass them as Unix timestamps:
In Django:
time_t = time.mktime(my_date.timetuple())
In JavaScript, assuming you've done something like time_t = {{ time_t }} with the results of the snippet above:
my_date = new Date();
my_date.setTime(time_t*1000);
Finally, pay attention to UTC - you'll want to have the Python and Django date functions exchange data in UTC to avoid embarrassing shifts from the user's local time.
EDIT : Note that the setTime in javascript is in millisecond whereas the output of time.mktime is seconds. That's why we need to multiply by 1000
2018 Update: I still like JSON for complex values but in the intervening decade the HTML5 data API has attained near universal browser support and it's very convenient for passing simple (non-list/dict) values around, especially if you might want to have CSS rules apply based on those values and you don't care about unsupported versions of Internet Explorer.
<div id="my-widget" data-view-mode="tabular">…</div>
let myWidget = document.getElementById("my-widget");
console.log(myWidget.dataset.viewMode); // Prints tabular
somethingElse.addEventListener('click', evt => {
myWidget.dataset.viewMode = "list";
});
This is a neat way to expose data to CSS if you want to set the initial view state in your Django template and have it automatically update when JavaScript updates the data- attribute. I use this for things like hiding a progress widget until the user selects something to process or to conditionally show/hide errors based on fetch outcomes or even something like displaying an active record count using CSS like #some-element::after { content: attr(data-active-transfers); }.
For anyone who might be having a problems with this, be sure you are rendering your json object under safe mode in the template. You can manually set this like this
<script type="text/javascript">
data_from_django = {{ my_data|safe }};
widget.init(data_from_django);
</script>
As of mid-2018 the simplest approach is to use Python's JSON module, simplejson is now deprecated. Beware, that as #wilblack mentions you need to prevent Django's autoescaping either using safe filter or autoescape tag with an off option. In both cases in the view you add the contents of the dictionary to the context
viewset.py
import json
def get_context_data(self, **kwargs):
context['my_dictionary'] = json.dumps(self.object.mydict)
and then in the template you add as #wilblack suggested:
template.html
<script>
my_data = {{ my_dictionary|safe }};
</script>
Security warning:
json.dumps does not escape forward slashes: an attack is {'</script><script>alert(123);</script>': ''}. Same issue as in other answers. Added another answer hopefully fixing it.
You can include <script> tags inside your .html templates, and then build your data structures however is convenient for you. The template language isn't only for HTML, it can also do Javascript object literals.
And Paul is right: it might be best to use a json module to create a JSON string, then insert that string into the template. That will handle the quoting issues best, and deal with deep structures with ease.
It is suboptimal. Have you considered passing your data as JSON using django's built in serializer for that?
See the related response to this question. One option is to use jsonpickle to serialize between Python objects and JSON/Javascript objects. It wraps simplejson and handles things that are typically not accepted by simplejson.
Putting Java Script embedded into Django template is rather always bad idea.
Rather, because there are some exceptions from this rule.
Everything depends on the your Java Script code site and functionality.
It is better to have seperately static files, like JS, but the problem is that every seperate file needs another connect/GET/request/response mechanism. Sometimes for small one, two liners code os JS to put this into template, bun then use django templatetags mechanism - you can use is in other templates ;)
About objects - the same. If your site has AJAX construction/web2.0 like favour - you can achieve very good effect putting some count/math operation onto client side. If objects are small - embedded into template, if large - response them in another connection to avoid hangind page for user.
Fixing the security hole in the answers by #willblack and #Daniel_Kislyuk.
If the data is untrusted, you cannot just do
viewset.py
def get_context_data(self, **kwargs):
context['my_dictionary'] = json.dumps(self.object.mydict)
template.html
<script>
my_data = {{ my_dictionary|safe }};
</script>
because the data could be something like
{"</script><script>alert(123);</script>":""}
and forward slashes aren't escaped by default. Clearly the escaping by json.dumps may not 100% match the escaping in Javascript, which is where the problems come from.
Fixed solution
As far as I can tell, the following fixes the problem:
<script>
my_data = JSON.parse("{{ my_dictionary|escapejs }}");
</script>
If there are still issues, please post in the comments.

Categories

Resources