Ruby - Sinatra: Asynchronously calling method with form input as parameter - ruby

I am currently trying to build a little widget that will retrieve a list of artists based on a username.
The Ruby method requires a username parameter after which an API call is made that retrieves the actual array of strings.
The web page has an input field where the user can fill out his/her username. My goal is to immediately call the ruby method and display the list of artists. My problem is being able to use the actual form input as the parameter. I figured this would be relatively easy with params[:user], in the same way it's done in a Sinatra post method. Alas, turns out it isn't.
I tried both a JS approach and directly calling the method after :onkeyup.
Javascript:
userChanged = function() {
var user = document.getElementById("username");
if (user.value.length != 0){
artists = #{RFCore::get_artists(:name => params[:user]).to_json};
art_list.innerHTML = artists
};
};
:onkeyup
:onkeyup => "art_list.innerHTML = #{RFCore::get_artists(:name => params[:user])[0]}"
I have substituted params[:user] with all variations I could think of such as "#{user}" and user.
The errors returned are undefined method []' for params[:user] and undefined local variable or methoduser' for "#{user}" and user.
Perhaps there is an easy solution to this; but the feeling is starting to creep up on me my approach is wrong to begin with. I am open to any other way of achieving this.

As far as I understood, you are generating that JavaScript dynamically. So when your Ruby code produces it, it evaluates that RFCore::get_artists expression when you are generating the JavaScript code, not when the user interacts with the web page.
If that's the case, I recommend:
Use jQuery. It makes your life much easier.
When there's some user interaction (e.g., a key press), use Ajax to communicate with your server to get back a list of artists.
Here is a small Sinatra application that demonstrates this approach:
require 'sinatra'
get '/' do
<<html
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
function userChanged()
{
$.get('/get-artists',
{username: $('#username').val()},
function(data){
$('#artists').html(data);
});
}
</script>
User: <input id="username" type="text">
<button onclick="userChanged();">Look up</button>
<div id="artists"/>
html
end
get '/get-artists' do
"Generate here list for user #{params[:username]}"
end
Please notice that the above code is just an example. The HTML generated is all wrong, no template language is being used, etc.

Related

Accessing Oracle ATG variables with Javascript

I am trying to pass the contents of a bean to javascript so that I can parse it and create a JSON object... (Yes I am still on ATG 9.1). However I am having trouble getting from serverside to client side.... I am new with this stuff and would appreciate any explanation as documentation on this is scarce and not helpful.
<dsp:tomap var="cartMap" bean="MyShoppingCartModifier.order" recursive="true"/>
<script>
var myCartMap = "${cartMap}";
//Logic (easy)
</script>
Doing this generates an "Uncaught SyntaxError: Unexpected token ILLEGAL" on my browser (Chrome)
Any wisdom will greatly help me in my quest in learning this stuff.
The problem is your usage of the tomap tag. You can't just pass in an entire tomap'd object because the tomap tag isn't going to create a nice, parsable json object.
You should either:
1) Format the json yourself right within your tags. Choose only the values that you want from the order.
<script>
var myCart = {
total : '<dsp:valueof bean="MyShoppingCartModifier.order.priceInfo.total">'
...
}
// Then use myCart for something here
</script>
or 2) There's a little known JSP to JSON library found here, http://json-taglib.sourceforge.net, that is very useful. To use that, you'd create a separate page, something like orderJSON.jspf, that is used to generate a pure json object from your order. Then in the page that you require this js, you can do:
<script>
var myCart = <%# include file="/path/to/orderJSON.jspf" %>
// Then use myCart for something here.
</script>

Sammy intercepts a POST that is not one of the added routes

I have an application that uses Sammy for some simple client-side routing.
One of the pages has a "Download Pdf" button, which needs to do a POST to get and download a pdf document (not very resty, I know, but it has to be a POST due to the large amount of data I'm submitting). It does this using the old trick of dynamically creating, populating, and submitting a <form> element.
Everything works fine, except for I can see in the console an error from sammy that my route was not found. Note that this is not a route, or even a verb that Sammy should be handling.
Here is my reduced test case
Sammy(function initializeClientRouting(app) {
app.get('#/', show('#default'));
app.get('#/test', show('#test'));
function show(selector) { return function() {
$('section').slideUp();
$(selector).slideDown();
}; }
}).run('#/');
$('button').click(function() {
var form = $("<form method=post action: 'http://www.google.com'>").hide();
$('<textarea name=q>').text("search text").appendTo(form);
form.appendTo('body').submit().remove();
});
Does anyone know how to prevent this error? Is this a bug in Sammy?
It's a combination of sammy & JQuery behaviour (bug?). When generated dynamically the way you put it, the form tag is being rendered as
<form www.google.com'="" 'http:="" action:="" method="post">
This will try to POST to the current page which probably is something like
http://blah/# or http://blah/#/test
For some reason, Sammy will be triggered because of the hashtag, not finding a POST configured and log an error.
Fiddling with your example, what worked for me was:
var form = $("<form>");
form.attr('method', 'post');
form.attr('action', 'http://www.google.com');
$('<textarea name=q>').text("search text").appendTo(form);
form.appendTo('body').submit().remove();
This seemed to generate the proper HTML and remove the Sammy error.

Send form to server in jquery

I am learning ASP.NET MVC. I have to submit a to controller side after validation in client-side(in jquery). How this can be done? Should i use <form action="#" method="post"> instead of <form action="Controller/Method" method="post"> and add an event handler in click event of submit button of , to send via ajax etc? What should i do? pls help
You are on the right track, and what you suggested will work.
A better method would be to leave the original action intact, providing backwards compatibility to older browsers. You would then create the event handler as normal, and include code to prevent the default submit behavior, and use ajax instead.
$('#submitbutton').live('click', function(e){ e.preventDefault(); });
The easiest way to do this is to use the jQuery forms plugin.
This is my go-to plugin for this type of thing. Basically it will take your existing form, action url etc and convert the submission to an ajax call automatically. From the website:
The jQuery Form Plugin allows you to easily and unobtrusively upgrade
HTML forms to use AJAX. The main methods, ajaxForm and ajaxSubmit,
gather information from the form element to determine how to manage
the submit process. Both of these methods support numerous options
which allows you to have full control over how the data is submitted.
It is extremely useful for sites hosted in low cost web hosting
providers with limited features and functionality. Submitting a form
with AJAX doesn't get any easier than this!
It will also degrade gracefully if, for some reason, javascript is disabled. Take a look at the website, there are a bunch of clear examples and demos.
This is how I do:
In jQuery:
$('document').ready(function() {
$('input[name=submit]').click(function(e) {
url = 'the link';
var dataToBeSent = $("form#myForm").serialize();
$.ajax({
url : url,
data : dataToBeSent,
success : function(response) {
alert('Success');
},
error : function(request, textStatus, errorThrown) {
alert('Something bad happened');
}
});
e.preventDefault();
});
In the other page I get the variables and process them. My form is
<form name = "myForm" method = "post">//AJAX does the calling part so action is not needed.
<input type = "text" name = "fname"/>
<input type= "submit" name = "submit"/>
<FORM>
In the action page have something like this
name = Request.QueryString("fname")
UPDATE: As one of your comment in David's post, you are not sure how to send values of the form. Try the below function you will get a clear idea how this code works. serialize() method does the trick.
$('input[name=submit]').click(function(e){
var dataToBeSent = $("form#myForm").serialize();
alert(dataToBeSent);
e.preventDefault();
})

getting value of several textarea from WYMeditor

I would like getting the value of two textarea from WYMeditor:
The first one:
<script type="text/javascript">
jQuery(function() {
$(" .wymeditor").wymeditor({
logoHtml: '',
lang: 'fr',
skin: 'default',
});
});
</script>
And the second one:
<script type="text/javascript">
jQuery(function() {
$(" .wymeditor_ref").wymeditor({
logoHtml: '',
lang: 'fr',
skin: 'silver',
});
});
</script>
HTML:
<textarea id="definition" class="wymeditor" name="definition"/></textarea>
<textarea id="references_definitions" class="wymeditor_ref" name="definition"/></textarea>
I'm using this: WYMeditor.INSTANCES[0].html();
But, the problem is I don't know how to do if there are two textarea. How getting the second value?
Thanks a lot!!
Get specific WYMeditor instance HTML with known ordering
If you simply want to iterate through the results of all the WYMeditor instances on a particular page, your array index method is just fine. If you know the order in which the WYMeditor instances are created, you'll do something like:
var wymResults,
wymRefResults;
wymResults = WYMeditor.INSTANCES[0].xhtml();
wymRefResults = WYMeditor.INSTANCES[1].xhtml();
Get HTML from all WYMeditor instances
If you have an unknown number of instances of WYMeditor, this is how you might get the results of all of them:
var results = [],
i;
for (i = 0; i < WYMeditor.INSTANCES.length; i++) {
// Do something with the xhtml results
results.push(WYMeditorINSTANCES[i].xhtml());
}
Get specific HTML results with unknown instantiation order
If it matters which WYMeditor instance you'd like to retrieve though, which is often the case, you'll want to store references to the specific instances when you create them. eg.
var wym,
wymRef,
wymResults,
wymRefResults;
// Instantiate my WYMeditor instances
wym = $(".wymeditor").wymeditor();
wymRef = $(".wymeditor_ref").wymeditor();
// Let's grab the results. This will probably live in some kind of `submit()` handler.
wymResults = wym.xhtml();
wymRefResults = wymRef.xhtml();
Use xhtml(), not html()
Another note specific to your example, but you should be using the xhtml() call instead of the html() call to ensure consistent, cross-browser markup.
The html() call doesn't run the resulting HTML through the parser or do any browser-specific cleanup, which means that if you were to load some html in lets say IE9 that was created in Chrome, just calling html() without making any changes will mean the resulting HTML will be slightly different. Different browsers need HTML that is slightly different to provide a consistent editing experience, and WYMeditor abstracts this away for you, assuming you use xhtml() to get the results.

knockout.js and Firefox Save Passwords on login form

Firefox populates a form with my username/password. This is using knockout.js to bind the input but it won't update the values on this kind of populating. Am I missing something say on a page load? When it populates and the user hits submits, the values are blank.
(function (app, $, undefined) {
app.viewModel = app.viewModel || {};
app.login = {};
app.viewModel.login = {
userName: ko.observable(''),
password: ko.observable(''),
returnUrl: ''
};
app.viewModel.login.submit = function () {
sso.login(app.viewModel.login.userName(), app.viewModel.login.password(), app.viewModel.login.returnUrl);
};
app.login.init = function (returnUrl) {
app.viewModel.login.returnUrl = returnUrl;
ko.applyBindings(app.viewModel);
};
})(window.app = window.app || {}, jQuery);
The way that I have dealt with this in the past is to use a wrapper to the value binding that initializes the value from the element's current value.
It would look like (this one is simplified to only work with observables):
ko.bindingHandlers.valueWithInit = {
init: function(element, valueAccessor, allBindingsAccessor, context) {
var observable = valueAccessor();
var value = element.value;
observable(value);
ko.bindingHandlers.value.init(element, valueAccessor, allBindingsAccessor, context);
},
update: ko.bindingHandlers.value.update
};
So, you would use valueWithInit instead of value. You just need to make sure that ko.applyBindings is not called before the autocomplete has been able to do its job.
http://jsfiddle.net/rniemeyer/TeFAX/
I found the solution here not really satisfying. Although the approach is rather interesting, it fails when the user is choosing the account later and the browser does allow to use the stored credentials (e.g. if there are more than one credentials stored). It failed as well when you started typing in the password and deleted to get back to the original password (in Firefox at least).
Additionally, I did not really like the timeout to give the browser time - just not that nice.
My solution:
which isn't really one, but I thought I share nonetheless
Simple update our model manually before doing the login in the submit callback.
Using jQuery, something like self.password($("#password").val()) should do it.
Alternatively, using the existing bindings, triggering a change event seems to work as well - e.g. $("#password").change().
The Pros:
is only for credential fields, so probably a one time thing for your site
is simple and clean - one or two lines at the proper place
seems to always work reliably, no matter what browser, credential setup or usage pattern
The Cons:
breaks again the nice separation Knockout.js provides
is not a solution but rather a workaround
I will stick with that for now because I found it just reliable working. It would be nice to tell Knockout to reevaluate the bindings directly rather than storing the value back manually or triggering it via the change event. But I haven't found anything so far.
Just thinking a bit ahead - the same problem should arise when the browser auto-completes any form (e.g. like an address) - which means means some sort of general function doing the above would be nice (probably calling the change trigger on each input field of the form)
Edit:
Some quick code demonstrating the idea
The HTML:
<form id="myForm" data-bind="submit: login">
Email: <input type="text" data-bind="value: email" /><br/>
Password: <input type="password" data-bind="value: password" /><br/>
<button type="submit">Login</button>
</form>
And the Javascript:
function ViewModel() {
var self = this;
self.email = ko.observable("");
self.password = ko.observable("");
self.login = function() {
$("#myForm").find("input").change();
//Now the observables contain the recent data
alert(ko.mapping.toJSON(self));
};
}

Resources