Use jquery with ejs template - javascript

I'm trying to use jquery in an ejs template to make an input auto complete using an array sent by the server to the template.I get the following error :
ReferenceError: /var/www/html/DM/views/formulaire.ejs:8
6| <title>Formulaire </title>
7| </head>
>> 8| <%
9| $( "#depart" ).autocomplete({
10| source: autoComp
11| });
$ is not defined
I made some researches and found out that you can't use client side javascript (jquery) with server side javascript (ejs), but i didn't find any solution.
Here is the code :
<!DOCTYPE html>
<html lang="fr">
<head>
<script src="https://code.jquery.com/jquery-3.1.1.js"></script>
<meta charset="UTF-8">
<title>Formulaire </title>
</head>
<body>
<script>
$( "#depart" ).autocomplete({
source: autoComp
});
</script>
<form action="/result" method="post">
Départ:<input type="text" name="depart" id="depart"><br>
Arrivée: <input type="text" name="arrivee"><br>
<input type="submit" value="Chercher un itinéraire">
</form>
<%
if(erreur){
%> <p>Erreur lors de la saisie des stations</p>
<%
}
%>
</body>
</html>
Thank you for your help
EDIT : No error anymore but auto completion doesn't work.

You need to put client side code in a <script> tag
Change
<%
$( "#depart" ).autocomplete({
source: autoComp
});
%>
To
<script>
$( "#depart" ).autocomplete({
source: autoComp
});
</script>
And put it inside the head or body

I assume you were creating the array in the action and passing it to the view. You then have to go one step further and pass it from the server-side view engine, to the actual browser engine.
<script>
let autoComp = JSON.parse( `<%= JSON.stringify( autoComp ) %>` );
What this does:
tells the EJS engine to render the array as a JSON string
(note the backticks, you need some kind of quotation mark because it's a string)
The browser-side JS engine then runs that string through JSON.parse
Obviously this ability only works one-way; to get a variable from the browser to the EJS you need to commit an action (POST/GET).
You may also need some substitutions to make the string play nice, such as:
function fixForJSON(val) {
return val.replace(/'/g, '&apos;').replace(/\\/g, '\\\\');
}
function fixForDisplay(val) {
return val.replace(/&apos;/g, "'").replace(/\\\\/g, '\\');
}
If you really want to do this:
<%
$(selector).doStuff();
You need to pass the JQuery object itself, into the template variables.
E.g. in your node code:
const jsdom = require('jsdom');
const jquery = require('jquery');
const { JSDOM } = jsdom;
const dom = new JSDOM(`<!DOCTYPE html><p>Hello world</p>`);
const $ = jquery(dom.window);
global.jq = $;
Then in your specific route action (still node code)
var locals = { // the var you are sending to the EJS template
jq: global.jq,
And finally in your EJS you can:
const $ = jq;
var testDiv = $('<div>').html('hello jquery in the template').appendTo('body');
console.log($('body').html());

Related

SketchUp WebDialog does not execute JS and action_callback

I have the following index.html:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Hello World</title>
<script>
function close() {
window.location.href = 'skp:closeDialog#someString';
}
</script>
</head>
<body>
<p id='data'>Text will go here...</p>
<button onclick="close()">Done</button>
</body>
</html>
And I have the following ruby script:
dlg = UI::WebDialog.new( "Hello World", "", false, 500, 300, 433, 234, false )
dlg.set_file( File.dirname(__FILE__) + 'index.html' )
dlg.add_action_callback( "closeDialog" ) {|dialog, params|
data = dlg.get_element_value( "data" )
puts data
dlg.close
}
dlg.show {
dlg.execute_script( "document.getElementById('data').innerHTML = 'Hello World!'" )
}
For some reason neither the script that should change the value of the <p> element nor the callback action does not work. The strange thing is, that if I change the JS to
dlg.execute_script( "alert('Hello World!')" )
then the alert message is shown upon start.
Any help is appreciated, thanks!
For the block in .show - the HTML might not be ready yet. Have a look at this article: https://github.com/thomthom/sketchup-webdialogs-the-lost-manual/wiki/window.onload
Given this script:
module TT_Test
#d = nil
#d = UI::WebDialog.new('On Load Test')
#d.add_action_callback('onload') { |dialog, params|
puts '>> window.onload'
}
#d.set_html('Onload Test')
def self.onload
#d.show {
puts '>> ruby block'
}
end
end
Windows:
load 'test/webdialog.rb'
true
TT_Test.onload
true
>> ruby block
>> window.onload
OSX:
> load 'test/webdialog.rb'
true
>> window.onload
> TT_Test.onload
true
Observe that the block in show isn't reliable in terms of the onLoad event.
What I always do is use jQuery's ready event and send a callback to Ruby - that way I know the dialog's content is ready. And only in that callback will I perform setup etc.
As for dlg.get_element_value( "data" ) - the data element in your code is a <p>: <p id='data'>Text will go here...</p>. get_element_value is working only for form elements.
Note that in your add_action_callback you have the params argument - that will contain the data after # in skp:closeDialog#someString.

Scrape html with js

I'm trying to get the html of www.soccerway.com. In particular this:
that have the label-wrapper class I also tried with: select.nav-select but I can't get any content. What I did is:
1) Created a php filed called grabber.php, this file have this code:
<?php echo file_get_contents($_GET['url']); ?>
2) Created a index.html file with this content:
<!DOCTYPE html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<meta charset=utf-8 />
<title>test</title>
</head>
<body>
<div id="response"></div>
</body>
<script>
$(function(){
var contentURI= 'http://soccerway.com';
$('#response').load('grabber.php?url='+ encodeURIComponent(contentURI) + ' #label-wrapper');
});
var LI = document.querySelectorAll(".list li");
var result = {};
for(var i=0; i<LI.length; i++){
var el = LI[i];
var elData = el.dataset.value;
if(elData) result[el.innerHTML] = elData; // Only if element has data-value attr
}
console.log( result );
</script>
</html>
in the div there is no content grabbed, I tested my js code for get all the link and working but I've inserted the html page manually.
I see a couple issues here.
var contentURI= 'http:/soccerway.com #label-wrapper';
You're missing the second slash in http://, and you're passing a URL with a space and an ID to file_get_contents. You'll want this instead:
var contentURI = 'http://soccerway.com/';
and then you'll need to parse out the item you're interested in from the resulting HTML.
The #label-wrapper needs to be in the jQuery load() call, not the file_get_contents, and the contentURI variable needs to be properly escaped with encodeURIComponent:
$('#response').load('grabber.php?url='+ encodeURIComponent(contentURI) + ' #label-wrapper');
Your code also contains a massive vulnerability that's potentially very dangerous, as it allows anyone to access grabber.php with a url value that's a file location on your server. This could compromise your database password or other sensitive data on the server.

How do I pass this JSON data to an autocomplete

Special thanks to Raúl Monge for posting a fully working code for me.
My problem was getting JSON data from a file.json and using this data to autocomplete search on it with JavaScript. The code that finaly got it working for me is the following:
<script>
$(document).ready(function(){
var arrayAutocomplete = new Array();
$.getJSON('json/telefoonnummers.json', function(json) {
$.each(json.personen.persoon,function(index, value){
arrayAutocomplete[index] = new Array();
arrayAutocomplete[index]['label'] = value.naam+" - "+value.telefoonnummer;
});
$( "#search" ).autocomplete({source: arrayAutocomplete});
});
});
This is the html:
<body>
<div id="content">
<input type="text" id="search" />
</div>
And this has to be included in the head:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css"/>
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
Thanks stackoverflow!
NEW EDIT CODE WORKING:
<script>
$(document).ready(function(){
var arrayAutocomplete = new Array();
$.getJSON('data.json', function(json) {
$.each(json.persons.person,function(index, value){
arrayAutocomplete[index] = new Array();
arrayAutocomplete[index]['label'] = value.name;
arrayAutocomplete[index]['value'] = value.phoneno;
});
$( "#search" ).autocomplete({source: arrayAutocomplete});
});
});
</script>
Add this in head
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css"/>
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
This is the html
<body>
<div id="content">
<input type="text" id="search" />
</div>
</body>
why not use
var data = [
"Aragorn",
"Arwen",
....
];
since all of those data are labels?
There you go
A working example with the data structure you have.
Just initialize the autocomplete once the JSON is loaded & the data is formatted.
$( "#search" ).autocomplete({source: availableTags});
Your document ready is within your function.
Try to write your function outside of your document ready.
Then write your document ready to call your function.
Some something like this:
function loadJson() {
//alert("Whoohoo, you called the loadJson function!"); //uncomment for testing
var mycontainer = [];
$.getJSON( "data.json" , function(data) {
//alert(data) //uncomment for testing
$.each( data, function( key, val ) {
//alert("key: "+key+" | val: "+val); //uncomment for testing
array.push([key , val]);
});
});
return mycontainer;
}
$(document).ready(function(){
//alert("Boojah! jQuery library loaded!"); //uncomment for testing
var content = loadJson();
dosomethingwitharray(content);
});
Hope this helps!
Also make sure you have jQuery included in your head ( <head> </head> ):
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
And add your javascript at the end of your body ( <body> </body> ).
To test if jquery does it's job try this:
<html>
<head>
<title>getting started with jquery</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
</head>
<body>
<h1>my page</h1>
<p>this paragraph contains some text.</p>
<!-- javascript at end -->
<script>
$(document).ready(function(){
//show a dialog, confirming when the document is loaded and jquery is used.
alert("boojah, jquery called the document ready function");
//do something with jquery, for example, modify the dom
$("p").append('<br /> i am able to modify the dom with the help of jquery and added this line, i am awesome.');
});
</script>
</body>
</html>
PS. Uncomment alerts for testing stuff, so you can test what happens. If you have space in your document i suggest using $.append to an div that log's all action's so you can see exactly what's going on because alert's in a loop like the .each are quite annoying! more about append: http://api.jquery.com/append/

Laravel 4 blade syntax within my javascript files

My home page had some inline javascript that was mixed up with some blade syntax e.g.
<script type="text/javascript">
#if(Auth::user())
if(path.indexOf('/user/' + {{Auth::user()->id}} ) != -1) {
$( "#tabs" ).tabs();
};
#endif
</script>
It worked until I wanted to move the javascript to an external file.js. I got error whenever blade syntax was added. Is there a way I can fuse blade syntax in my javascript files.js? I tried renaming to file.blade.js with no luck...
Although the accepted solution will work, this is a most definitely an antipattern.
If I saw this not being the one who wrote it, I would be extremely confused to what's going on.
My suggestion is in your PHP file, have a block, which gets all of the values that you'll need in your external files, then call the external files.
So in your PHP file you would have something like:
<script>
var userID = "{{ Auth::user()->id }}";
var isUser = "{{ Auth::user() }}"
</script>
{{ HTML::script('path/to/js/file.js') }}
And in your javascript file:
if(isUser)
{
if(path.indexOf('/user/' + userID ) != -1) {
$( "#tabs" ).tabs();
};
}
you can try this save your javascript file in app/views folder and rename it to xxx.blade.php , yes .blade.php because Blade Engine will parse it only if its .blade.php and use #include('your javascript filename') to include the javascript file parsed by Blade, it will work.
I was doing the same than #BrandonRomano, but I found a better approach. Sending directly the value from PHP to JS vars using:
PHP-Vars-To-Js-Transformer
PHP:
JavaScript::put([
'foo' => 'bar',
'user' => User::first(),
'age' => 29
]);
JS:
console.log(foo); // bar
console.log(user); // User Obj
console.log(age); // 29
You can set a namespace like:
console.log(server.foo)
You are outputing string from PHP, so you have to enclose that string in '
<script type="text/javascript">
#if(Auth::user())
if(path.indexOf('/user/' + '{{Auth::user()->id}}' ) != -1) {
$( "#tabs" ).tabs();
};
#endif
</script>

Trying to parse xml file for javascript quiz

I am trying to create a javascript quiz, that gets the questions from a xml file. At the moment I am only starting out trying to parse my xml file without any success. Can anyone point me to what I am doing wrong?
<html>
<head>
<title>Test</title>
<script type="text/javascript" src="prototype.js"></script>
</head>
<body>
<div class="spmArr">
</div>
<script type="text/javascript">
var quizXML = '<quiz><Sporsmal tekst="bla bla bla"/><alternativer><tekst>bla</tekst><tekst>bli</tekst><tekst correct="yes">ble</tekst></alternativer><Sporsmal tekst="More blah"/><alternativer><tekst>bla bla</tekst><tekst correct="yes">bli bli</tekst><tekst>ble ble</tekst></alternativer></quiz>'
var quizDOM = $.xmlDOM( quizXML );
quizDOM.find('quiz > Sporsmal').each(function() {
var sporsmalTekst = $(this).attr('tekst');
var qDiv = $("<div />")
.addClass("item")
.addClass("sporsmal")
.appendTo($(".spmArr"));
var sTekst = $("<h2/>")
.html(sporsmalTekst)
.appendTo(qDiv);
});
</script>
</body>
</html>
When I try this in my browser the classes and div are not being created. And the page is just blank. Am i doing something wrong when I intialize the xml?
edited to add prototype.js and close function
Looks like you're forgetting to close your .each call. append ); after the statement for sTekst and your call will parse correctly.

Categories