Is there a way to implement if statements inside :javascript filter with HAML in Rails?
I've tried various ways such as
:javascript
$(function(){
- if #booth.greeting_video?
= $('#greeting_video').modal();
But they do not seem to be working at all.
Is there a clean way of implementing this?
The filters in HAML are processed separately from the other code, and the only thing allowed here is the #{} method, which just inserts a Ruby value.
Theoretically you can insert your condition there, and return different values depending on it. And I can't guess what you're trying to do with = $('#greeting_video').modal(); - it looks like javascript, but why is there = sign before, making it look like ruby insertion?
And, it also needs to be said, it's not really a good idea to mix up back-end and fron-end so much. The js variable can be set here, and somewhere in another file the modal would be rendered or not, depending on that variable (just another way suggestion)
Related
I'm having a little issue here, we are bussy with our internship and are still learning so sorry in advance for some "stupid" questions.
We have a Haml file where we make use of datamapper for our Database.
For static views based on our data, we make use of datamapper-code lines in haml.
But now I wanted to use a Javascript variable, who's located in the pageload function, to use this as a parameter with our datamapper code lines in haml.
In our javascript:
$(document).ready(function(){
var ctrpersiteid = $.cookie('sitedata');
Part of our Haml file where we want to use our variable ctrpersiteid
- Interface.all(:router_id => getRouterId(ctrpersiteid)).each do |interface|
%h3 #{interface.name}
So is there any way that I could use my Javascript variable in the haml file as parameter for our function ?
The short answer is no. Javascript is only executed in the clients browser, so there's no way to access it from your server-side haml template.
I have a rails application which is serving up a number of views which include specific data from the database to be manipulated by some javascript, specifically for use with Chartjs.
Options I have explored are:
Use an ajax call to pull the data off the server. I don't like this one because the user isn't changing any data, I have access to all the data when I render the page, there ought to be a better way.
Use <script> tags in the view ERB and simply have ERB interpolate the variable. This seems a little hacky and definitely doesn't take advantage of all my beautiful haml. But it is easy and allows me to put javascript variables on the page which can then be picked up after the document.onload.
Gon. Great gem and very easy. But should this really require a gem?
I feel as though the solution should involve the asset pipeline and some sort of rails interpolation, but I can't seem to make that work very cleanly. What is the elegant rails 4 way for solving this?
Thanks everyone!
There are many ways to pass data from server-side to javascript, I'll list two of the most common (that don't use a gem or other external tools) below:
Use the second method you described, and interpolate ERB tags inside the javsacript. This is ugly, hacky and is not even close to best practice.
Use data attributes. You can modify your HAML to include additional attributes, like "data-my-variable", and access it via javascript (example using jQuery: $(element).data("my-variable")).
The data attribute method is, in my opinion, the cleanest way of doing this, it's exactly the purpose of data attributes.
Now, I don't know HAML, I've only worked with ERB before, but I found this answer by Mandeep, which explains how you can add data attributes to your HAML:
%a{"data-my-variable" => "my data", href: "#"}
OR
%a{href: "#", :data => {:my_variable => "my data"}}
EDIT: Sorry, I found your question along with other, newer, questions, I just assumed it was recent, and not from over a year ago :)
For a Rails 3.1 app, some of my site wide JavaScript is only included when certain real time, instance specific conditions are met. This means I can't put it in the new asset pipeline's application.js because that isn't parsed by erb for embedded Ruby within the current context. Basically, I'm including keyboard shortcuts, based on the current_user that is logged in.
My question: where should this JavaScript with embedded code go, so that the embedded Ruby is still parsed for each page access with the proper context (i.e. current, logged in user)?
The answer seems to just be to put it in the application.html.erb layout view at the bottom, but this seams like I'm hiding away javascript code in a non intuitive location.
I've tried creating an application2.js.erb file, but then I got errors about undefined variables, which I think might be because the asset engine only parses this file once before the output is cached and the scope isn't correct yet for things like current_user.
So, using application.html.erb works just fine here, and this isn't so much a question of how to get it to work functionally. Instead, I'm wondering if there's a more elegant way to incorporate the asset pipeline model here with my requirements and still keep most of my JavaScript in the assets/javascripts directory.
You should try to create app/assets/javascripts/application2.js.erb (or whatever better name you come up with)
And then put something like this in your app/assets/javascripts/application.js:
//= require application2
And then you can have
<%= javascript_include_tag 'application2' %>
wherever you want - for example in your application.html.erb.
Btw, if you want to customize what's included on a per-view basis you might find content_for useful. Check out this screencast
Ok, about unobtrusive js. It will be just a cocept (HAML):
In your view somewhere
# hotkeys are "Ctrl+C", "Ctrl+A"
-current_user.hotkeys.each do |hotkey|
%hotkey{ "data-key" => hotkey.key, "data-behavior" => hotkey.fn }
Then in your application.js
$(document).ready(function(){
if($("hotkey").length > 0){
$("hotkey").each{function(this){
key = $(this).data("key");
fn = $(this).data("behavior");
$(document).bind('keydown', key, fn);
}}
}
})
So just the same JS will extract from HTML hotkeys data and then bind it.
As some people have pointed out, the two options are:
Put your javascript inside the view (and as you say, this doesn't feel quite right).
Put it in a javascript file. Make a conditional inside your view that includes this javascript file if certain conditions are met.
If you need to pass more instance variables from the controller to your javascript, this gem called gon can make your life easier.
This allows you to use the default asset pipeline using the following javascript:
if(gon.conditional){
//your embedded js code here
}
If you want to know more about this gem, checkout this railcast where everything gets explained.
Sorry I'm a newbie to Ruby on Rails. I'm very confused about the big picture, so your help would be appreciated.
In my application.html.haml, I call =yield, which takes its output from ranked.html.haml. Now, the latter has access to the rails variable #featured_image.
What I want to do is to get hold of this rails variable #featured_image on page load, so that I can preload that image and images with ids right after that.
But my window.onload = function() in application.html.haml has no access to #featured_image...
how do I do this??
Thanks!!
As Chris Heald noted, the #featured_image variable is an instance variable on the controller, and you have access to it in your views. To use it from javascript, what you'll basically have to do is write it into your layout or partial somewhere in a script block like this (this is erb, not haml):
<script>
var featured_image="<%= #featured_image %>";
</script>
Obviously, you'll want to add in a check for nil value in #featured_image and handle it in a way that's appropriate for your app, or otherwise ensure that its always set to something. Chris's suggestion to use a helper is also a good one but I wasn't sure it was obvious what the helper would need to do for a newbie.
If #featured_image is set from a controller, it will be visible to all views in the render pipeline. You just can't necessarily always assume that it's visible, though, since a layout will potentially render many pages, so you'll want to check that it's there before attempting to use it from the layout.
I'd recommend using a helper method to check to be sure it's not nil, and then write out the proper markup. You might also look at content_for, which lets you mark blocks of markup to be rendered in other parts of the layout.
I'm developing a facebook app right now all by my lonesome. I'm attempting to make a javascript call on an onclick event. In this onclick event, I'm populating some arguments (from the server side in php) based on that item that is being linked. I'm inserting a little bit of JSON and some other stuff with funky characters.
Facebook expects all the attribute fields of an anchor to be strictly alphanumeric. No quotes, exclamation marks, anything other than 0-9a-Z_. So it barfs on the arguments I want to pass to my javascript function (such as JSON) when the user clicks that link.
So I thought, why don't I use my templating system to just autogenerate the javascript? For each link I want to generate, I generate a unique javascript function (DoItX where X is a unique integer for this page). Then instead of trying to pass arguments to my javascript function via onclick, I will insert my arguments as local variables for DoX. On link "X" I just say onclick="DoX()".
So I did this and viola it works! (it also helps me avoid the quote escaping hell I was in earlier). But I feel icky.
My question is, am I nuts? Is there an easier way to do this? I understand the implications that somehow somebody was able to change my templated local variable, ie:
var local = {TEMPLATED FIELD};
into something with a semicolon, inserting arbitrary javascript to the client. (and I'm trying to write code to be paranoid of this).
When is it ok (is it ever ok) to generate javascript from the server? Anything I should look out for/best practices?
Depending on your application generating JavaScript in your templating language can save a lot of time but there are pitfalls to watch out for. The most serious one being that it gets really hard to test your JavaScript when you don't have your full templating stack available.
One other major pitfall is that it becomes tempting to try and 'abstract' JavaScript logic to some higher level classes. Usually this is a sign that you will be shaving yaks in your project. Keep JavaScript login in JavaScript.
Judging from the little bit of information you have given it your solution seems sensible.
If you must generate javascript, I would suggest only generating JSON and having all functions be static.
It more cleanly separates the data, and it also makes it easier to validate to prevent XSS and the like.
JS generated from server is used in lots of areas. The following is the sample from a ASP.NET page where the JS script is generated by the framework:
<script src="/WebResource.axd?d=9h5pvXGekfRWNS1g8hPVOQ2&t=633794516691875000" type="text/javascript"></script>
Try to have reusable script functions that don't require regeneration; and 'squeeze' out the really dynamic ones for server-side generation.
If you want to feel better about it, make sure that most of your JavaScript is in separate library files that don't get generated, and then, when you generate code, generate calls to those libraries rather than generating extensive amounts of JavaScript code.
it's fine to generate JS from the server. just bear in mind not to fine too big a page from the server.
Generally speaking I avoid ever automatically generating JavaScript from a server-side language, though I do however; create JavaScript variables that are initialized from server-side variables that my JavaScript will use. This makes testing and debugging much simpler.
In your case I may create local variables like the following which is easy to test:
<script type='text/javascript' language='javascript'>
<!--
var FUNC_ARG_X = <%= keyX %>;
var FUNC_ARG_Y = <%= keyY %>;
var FUNC_ARG_Z = <%= keyZ %>;
//-->
</script>
<script type='text/javascript' language='javascript'>
<!--
function DoCleanCall(arg) {
// Whatever logic here.
}
//-->
</script>
now in your markup use:
<a href='#' onclick='DoCleanCall(FUNC_ARG_X);'>Test</a>
Now of course you could have embedded the server-side variable on the <a/> tag, however it is sometimes required that you refer to these values from other parts of your JavaScript.
Notice also how the generated content is in it's own <script> tag, this is deliberate as it prevents parsers from failing and telling you that you have invalid code for every reference you use it in (as does ASP.NET), it will still fail on that section only however.