Rails UJS data-disable-with return result - ruby-on-rails-3

I'm using Rails 3's UJS (which is awesome btw). I have the following form HTML:
<form accept-charset="UTF-8" action="/users/invitation" class="simple_form form-invite" data-remote="true" method="post">
<input class="btn btn-mini btn-invite" data-disable-with="Inviting" name="commit" type="submit" value="Invite">
</form>
I'm using data-disable-withso the button text changes and button is disabled during processing. However, I'd like the button text to change to "Invited" after the call is complete.
I'm using the following:
$(document).on "ajax:success", ".form-invite", (evt, data, status, xhr) ->
el = $(this).find('.btn-invite')
el.val("Invited")
return
This does change the button text. However, since it's processing within the ajax:success block, the button text reverts back to "Invite". Is there any way to define the button text after processing using HTML attribute or JavaScript?

I was able to fix this with a minor hack:
$(document).on("ajax:success", ".form-invite", function(evt, data, status, xhr) {
var el;
el = $(this).find('.btn-invite');
setTimeout((function() {
return el.val("Invited");
}), 1);
});

Related

Waiting for element to appear on static button in TestCafe

I have a strange behavior of TestCafe on my site. I have two checkboxes on a site and a button that brings me to the next step as soon as I click on it. When the page load, de button is visible and does not get manipulated at any time.
Here is the markup of the button:
<button id="confirmation-submit" type="submit" class="btn btn-success pull-right hidden-xs">
<span class="glyphicon glyphicon-flag"></span>
order now
</button>
Here is what my code looks like (the relevant part for this problem):
const submitOrderBtn = Selector('button[type="submit"].btn-success');
//const submitOrderBtn = Selector('#confirmation-submit');
test('complete order', async t =>{
await t
.click(submitOrderBtn)
In chrome it shows me this picture:
The output of the command line is this:
The button is visible the whole time and even when I look over the site with the developer tools, the button is there and it has the id (confirmation-submit) that I want to be clicked.
How can I get around this problem? On other pages, I can use the .click function without any problems.
As #Andrey Belym mentioned in his comment, TestCafe will consider element visibile if its width or height have a non-zero value and it is not hided using CSS properties like display: hidden and visibility: none.
You can check it in Computed CSS Properties in DevTools. In your case, #confirmation-button might be an invisible button hidden somewhere in an actual visible element.
Also, you can try to resize browser window using resizeWindow action. It may help if your layout is adaptive or it is a scrolling issue.
As a workaround you could try to click on the button parent container:
const submitOrderBtn = Selector('#confirmation-submit');
const confirmSelector = submitOrderBtn.parent();
test('complete order', async t =>{
await t
.click(confirmSelector)
if this does not work for the immediate parent, you could try to fetch the first parent div like this:
const submitOrderBtn = Selector('#confirmation-submit');
const confirmSelector = submitOrderBtn.parent('div');
test('complete order', async t =>{
await t
.click(confirmSelector)
<button data-se-id="confirmation-submit" type="submit" class="btn btn-success pull-right hidden-xs">
order now
</button
and in test add like this : for click specified element :
const submitOrderBtn =Selector('[data-se-id="confirmation-submit"]')
test('complete order', async t =>{
await t
.click(submitOrderBtn)

How to create two Action Results in Controller form the same view MVC?

I would like to have two buttons in my view (called Create), one that submits the form and takes the user back to home page if they are finished and one that submits the form but reloads the rating page to be able to add additional ratings.
Here is the problem that I have right now-
Currently I have one button that has an action result in my controller:
public ActionResult Create(Rating rating)
{
if (ModelState.IsValid)
{
db.Ratings.Add(rating);
db.SaveChanges();
return RedirectToAction("Index");
}
**Additional code that is irrelevant here
}
The problem that I am faced with is that this ActionResult has a Redirect in it to the homepage so when I submit my other button and use this same ActionResult class it is being redirected to the homepage. I am using the javascript onclick event in the view to redirect to the Ratings page when the button is clicked and the form is submitted but if I use this same Action Result class for both buttons it redirects the button I want to keep me on the page to the index page.
How do I create two Action Result classes from the same view, one for each submit button?
Well, how do you determine what the user wants to do?
Both buttons submit the form, so they may as well still use the same action. But you need to differentiate somehow. You can do that with the buttons.
Let's say you have these two buttons:
<input type="submit" name="redirect" value="true" />
<input type="submit" name="redirect" value="false" />
Then you can bind that in your action method:
public ActionResult Create(Rating rating, bool redirect)
{
// other logic
if (redirect)
return RedirectToAction("Index");
else
return View(rating);
}
If you are ever going to have more than two possible options then you might use a string instead of a boolean. Something like:
<input type="submit" name="action" value="redirect" />
<input type="submit" name="action" value="reload" />
And then in the controller:
public ActionResult Create(Rating rating, string action)
{
// other logic
if (action.Equals("redirect"))
return RedirectToAction("Index");
else if (action.Equals("reload"))
return View(rating);
else if //...
//... and so on
}
The point is that the client-side code needs to tell the server-side code what to do somehow. Including that on the form submission itself makes the form submission self-describing and allows the server-side code to handle it easily.
Example of how it use
Html, inside form:
<button type="submit" name="TaskSubmitAction" value="ActionReject" class="btn btn-danger pull-left">Reject</button>
<button type="submit" name="TaskSubmitAction" value="ActionSubmit" class="btn btn-success">Accept</button>
Controller:
public ActionResult TaskSubmit(int? id, string TaskSubmitAction)
{
switch (TaskSubmitAction)
{
case "ActionSubmit":
break;
case "ActionReject":
break;
default: throw new Exception();
}
In your html give both buttons the same 'name' attribute but assign two different values.
<button name="submitBtn" value="valueX"> Button 1 </button>
<button name="submitBtn" value="valueY"> Button 2 </button>
In your server side code get the value of the input button and based on this value carry out different actions
String choice = request.getParamter("submitBtn");
if(choice.equals("valueX"))
//do something
else if(choice.equals("valueY"))
//do something else

Upload file to hidden input using protractor and selenium

I've got a hidden file input field like this:
<input type="file" id="fileToUpload-1827" multiple="" onchange="angular.element(this).scope().setFiles(this)" data-upload-id="1827" class="hidden-uploader">
I'd like to be able to upload files to this. The normal way to do this in protractor would be to do:
ptor.findElement(protractor.By.css('.file-upload-form input')).sendKeys('/path/to/file')
But because the input element isn't visible, I get an error.
I tried:
ptor.driver.executeScript("return $('.file-upload-form input')[0].removeClass('hidden-uploader');").then(function () {
ptor.findElement(protractor.By.css('.file-upload-form input')).sendKeys('hello');
})
But got the error
UnknownError: $(...)[0].removeClass is not a function
It seems ridiculous to have to use executeScript to make an element visible so that I can upload a file, is there a better way? If not, how do I unhide the element?
The full html for the input form is:
<form class="file-upload-form ng-scope ng-pristine ng-valid" ng-if="ajaxUploadSupported">
<strong>Drag files here to upload</strong> or
<label for="fileToUpload-1953">
<div class="btn btn-info select-file-btn">
Click to Select
</div>
</label>
<div>
<input type="file" id="fileToUpload-1953" multiple="" onchange="angular.element(this).scope().setFiles(this)" data-upload-id="1953" class="hidden-uploader">
</div>
</form>
The only way I could find to do this in the end was to use javascript to make the input element visible.
So I have a function unhideFileInputs:
var unhideFileInputs = function () {
var makeInputVisible = function () {
$('input[type="file"]').removeClass('hidden-uploader');
};
ptor.driver.executeScript(makeInputVisible);
}
This contains the function 'makeInputVisible' which is executed in the browser when I call ptor.driver.executeScript(makeInputVisible). Because I know my page contains jQuery I can use the jQuery removeClass method to unhide my file input element.
To see more on how to execute javascript in the browser using webdriver, see the answer to this question (although the answer uses executeAsyncScript rather than executeScript).
To add on user2355213s answer for the more current releases of protractor. ptor is obsolote and instead browser should be used. Also, executeScript() expects a string as parameter. So I ended up using
browser.executeScript('$(\'input[type="file"]\').attr("style", "");');
as my visibility setting was directly applied to the element. Of course, you can also use
browser.executeScript('$(\'input[type="file"]\').removeClass("hidden-uploader");');
depending on your HTML/CSS.

Calling Post method using HTML.ActionLink

I have read multiple posts on similar issue but did not work.
I have fixed footer buttons and facing issue in calling "Post" version Edit action in Project controller. Here is what I'm trying to do
Let me know if question needs further explaination.
(I tried using Ajax.ActionLink which is suggested in multiple posts too but did not work out.
Similar Question
Finally I managed to fix it by some workarounds. Posting solution here to help someone.
Like I said earlier, I tried using Ajax.ActionLink but I was not able to achieve the same. Instead I looked for Calling Form Submit action from outside of form that's what I actually need here.
Form: Name your Form something, say "editProjDetailsForm"
#using (Html.BeginForm(null, null, FormMethod.Post,
new { #class = "form-horizontal",
name = "editProjDetailsForm" }))
Footer: Call this method from the footer button.
<input type="button" onclick="document.editProjDetailsForm.submit();"
class="btn btn-primary"
value="Save Changes" />
I tried this one too in footer but it did not workout:
#Ajax.ActionLink("Save Changes", "Edit", new { id = Model.ProjectId },
new AjaxOptions { HttpMethod = "POST" })
Helpful Posts
Naming A form using Begin Form
Submit Button outside HTML.BeginForm
Submit Button outside HTML.BeginForm (another link)
ASP.net ActionLink and POST Method
Error in case you have parameterized constructor in ViewModel and
did not declare parameterless constructor
Display Issue if you are using bootstrap In footer I had one input type = button and one action link with class= button. Both nested in one btn-group but there height were appearing different as visible in following snapshot:
Fix: Found that it is a known issue and there is one suggested solution but did not work out much for me (i.e. for Internet Explorer).
input type=submit and anchor button in btn-group appear as different sizes
Solution: add .btn { line-height:normal!important; } or if you want to do only for a specific button lets say the above input button then do this:
<input type="button" onclick="document.editProjDetailsForm.submit();"
class="btn btn-primary"
value="Save Changes"
style="line-height:normal!important;" />

Pass text box value to a dojo grid's query parameter

I am trying to pass the value in a text box as a query parameter in a dojo data grid and would like to get clarified on two questions listed below. The dojo grid initiates a call to the server with the query params to initiate a search and bring back results (that is diplayed on the data grid)
Is it possible to reload the gird based on the value in the text by invoking refresh (dijit.byId("mygrid").refresh
If yes, how can I pass the value of the text box as a query parameter to the data grid.
Listed below is my relevant code
function reload(){
dijit.byId("mygrid").refresh;
}
<div class="test">
<input id="searchParam" >
<button dojoType="dijit.form.Button" type="submit" onclick=reload()>
Search
</button>
</div>
<div dojoType="dojox.grid.DataGrid"
id="mygrid"
jsid="mygrid"
store="dojox.data.JsonRestStore"
target="<c:url value='members' />">
query="{
searchCriteria: ? TODO How to pass value of text box here?,
}"
rowsPerPage="1000"
autoWidth="true"
autoHeight="true"
selectionMode="single"
selectable="true"
errorMessage="Error loading data"
noDataMessage="<span class='dojoxGridNoData'>No members found.</span>">
</div>
You should be able do something like the following:
function reload() {
var val = dojo.byId('searchParam').attr('value');
dijit.byId("mygrid").setQuery({ propName: val });
}
You will need to properly build the query { propName: val }.