Pass instance variable to js Rails - javascript

In my search controller I have an instance variable, #results. I set it to return a dummy result, 'foo'.
In my search.html.erb view... I set window.results = <%= raw #results.to_json %>.
At the top of my search.js asset file, I console.log(results) and get undefined, but when I get into the devtools after the page load, results is populated with 'foo'. The console.log statement is also wrapped in a jquery ready function.
What gives?

Rails assets are precompiled so they don't have access to instance variables coming from the controller. Embed the Javascript directly into your view using a script tag and access the #results just like you did. You could also initiate a call to an external Javascript file.

Related

Using Ruby Variables in JavaScript

I'm new to Ruby so I had a question in regards to using some variables throughout my codebase. I have a variable declared in my Ruby file as follows:
#pages = 350
Now, I know that in HAML, I can simply do:
-if #pages = 350, and in HAML with inline javascript, I can do something like:
:javascript
console.log("#{#pages}");
However, I am linking an external JavaScript file in my HAML document, and I was wondering if it would be possible to use my Ruby variables in my external JS document? I need some variables in order to build what I am trying to build. Thanks!
Update as per one of the answers:
In my HAML file, I have the following:
:javascript
printPages(3);
In my external JS file, I have:
$(function() {
window.printPages = function(pages) {
console.log(pages);
}
});
I you are loading static javascript files I really would not recommend trying to insert variables into that code.
Instead, think about how you would provide that to your javascript code.
You could send it to that code as an argument.
<script type="text/javascript" src="./my-external-script.js"></script>
:javascript
runMyExternalFunction(#{#pages})
Or you could add the variable as a data attribute on your page, and your javascript could look for that when it loads.
Haml:
%body data-pages=#pages
JS:
console.log(document.body.dataset.pages) // value of #pages
Update about your javascript:
Using jquery's on page ready event $() for declaring the function is a bad idea. That means that it waits for everything on the page to be compeletely loaded, and then declares the function your page needs.
What you should be doing is setting up all the function that will be needed right away, and then calling those functions when the page is loaded.
They way you have it, the page loads, printPages() is executed (which doesn't exist yet), and then after all that printPages is created and put into the global scope.
So remove the $() from your external script and add it to your HAML instead.
In fact, if your aren't doing anything super fancy with transpiling or bundling, then you can simply declare the function in your external JS file, and it will be available globally. This doesn't work with your code because they way you've declared the function, it would only be available to code within that $() callback.
// js file
function printPages(pages) {
console.log(pages);
}
HAML:
$(() => {
printPages({#pages})
})

Ajax Load Static Rails Partial

In my rails app, I have a html template located in public/templates/_hero-1.html.erb
In my application.js.erb file, I'm trying to load that template into a div I created dynamically, before I render the entire div.
// Append component to text editor when clicked
$('.js-TemplateThumbnail').click(function() {
// Define new template container
var newTemplateContainer = $('<div class="position-relative hideChild js-TemplateContainer">');
// Insert selected template into new template container
newTemplateContainer.load("<%= 'public/templates/hero-1' %>");
// Build new template
$('.js-Canvas .js-TemplateContainer').last().after(newTemplateContainer);
});
But I'm getting a console error GET http://localhost:3000/public/templates/hero-1 404 (Not Found)
Quick answer/related SO answer: Rendering partial in js.erb file
Longer answer: There are a couple ways of doing this. You could try:
newTemplateContainer.load("<%= 'render partial: public/templates/hero-1' %>");
Not positive that will work. This feels hacky to me and also leaves you with highly coupled code. If the name of that template changes, you will have to update it in n places.
I would decouple the JS and create an internal endpoint in config/routes.rb; eg:
get templates/:id
then,
class TemplatesController < ApplicationController
def show
#template = Template.find(params[:id])
end
end
Then in your JS inside the click handler you can:
$.get('/templates/hero-1', function(data) {
// do stuff with returned data
$('.js-Canvas').html(data)
});
Very simplistic, but more so trying to outline a different approach. This also seems like something that handlebars could help with.

using controller variable in javascript in phoenix

Is it possible to use a variable which is passed from controller to view in render parameters to be used in javascript and how to do it?
The variable passed from controllers can be used in javascript as following:
<script type="text/javascript">
alert("<%= #var %>")
</script>
Another way you can use PhoenixGon it generates script tag with variables and additional methods for simplicity. It generate all stuff for you. You only need to use it from window.Gon or wundow.YouApplicationNamespace. And you don't need other rendering and data attributing in html.
In controller:
def index(conn, _params) do
conn = put_gon(conn, :variable, :value)
render conn, "index.html"
end
In js module or browser console:
window.Gon.getAsset('variable')
# => 'value'
It also keeps Mix.env for using in js.

Call Javascript Function before Razor calls my HTML Helper

I've been working on a HTML helper which will hide or show menu items depending on what type of user you are.
For this reason, In one of my controllers I am setting a session variables with values such as "ADMIN"
context.Session["perfil"] = "ADMIN"
The problem I am facing is that the Helper function is being called before the Javascript function which calls the controller that sets the session variables
This is how I call my HtmlHelper (through Razor)
#using XSiteManagerWeb.Helpers
#Html.Raw(Html.MiMenu("../Home/Configuracion", "ConfiguraciĆ³n"))
From my _Layout.cshtml
But before doing that I'm calling the function
<script type="text/javascript">ObtenerDatosSesion();</script>
Which calls a Controler method through Ajax
...
$.ajax({
url: "../Home/ObtenerDatosSesion",
....
Question: Why is the HtmlHelper being called before ObtenerDatosSesion(); even though I've put it before on the _Layout.cshtml ?
I've also tried calling in on window load doing this:
<body class="Fondoblue" onload="ObtenerDatosSesion();">
among other methods.
I noticed the Helper is being called before everytime after many debuggings. What I can't figure out is why that happens.
I wonder if it has anything to do with the Web.config line one has to put to use html helpers
<add namespace="XSiteManagerWeb.Helpers"/>
So to make it clear, I just want to make my "ObtenerDatosSesion(); method gets called before my html helper!
The razor helpers are executed server side, therefore they will be executed before any JS is rendered/executed on the page.
I would recommend moving whatever logic is in your ../Home/ObtenerDatosSesion endpoint to the same endpoint as ../Home/Configuracion. If it's going to be called more than once, you can put it in its own method.

How would I pass data to an external script loaded with $.getScript()?

So I'm trying to load a javascript remotely using jquery's $.getScript, but I'm puzzled on how I can pass data to the external script.
I've tried setting variables before the call but they aren't available in the script that gets loaded, and when I try to send/retrieve them using the query string, the remote script tries to read the querystring of the base file that it gets called from, not itself. Is there any other way to do this? Or is it possible to have a javascript file read its own querystring rather than the file it's called from (that's loaded in the browser)?
// editor ini
var editor_ini = { page: current_page, action: 'edit' };
var foo = 'bar';
// load the editor
$.getScript('assets/desktop/desklets/'+launcher.config.editor+'/execute.js', function(){});
In the execute.js file, the editor_ini and foo are both unavailable, I get the same result with:
// load the editor
$.getScript('assets/desktop/desklets/'+launcher.config.editor+'/execute.js', { page: current_page, action: 'edit', foo: 'bar' }, function(){});
because the remote script seems to be getting the query string from the original document rather than the one used when calling the file.
If it matters, I was trying to use the query object plugin for jquery for reading the query string.
global variable declared in inline javascript is accessible in external javascript page loaded using $.getScript().
I bet that your var foo='bar' is inside a function, so not visible in global scope. Try:
window.foo = 'bar'
Truly global variables will be accessible to your script. So, if they aren't, then it's probably because your variables that you think are global actually aren't. You can either move them to the top level scope or set them on the window object like Alexei suggested.
There are other ways to share data.
1) You can put an id on the <script> tag that loads the code and then have the code get the .src value from that tag and get the query string off the script's actual URL. I like this option, but I don't know if you can do it using jQuery.getScript() since I don't think it exposes that as an option.
2) You can have the loading script call a function that you provide and return an object with the desired data from that function.
3) Once the new script is loaded, you can call a setXXX() function in that script to set the state that it needs.
4) You can set information into a cookie that the other script can read.
5) You can encode data into a URL hash value that the other script can read.

Categories

Resources