fields nested in table are decorated twice after page switch - jquery-mobile

I get a table to be filled in data by JavaScript, there is a table with single template row with few columns, and are hidden by css, when server returns data, program clone the template row to multiple rows and fill in data to columns of them.
Now, there is a strange thing, if the table is in same page, all things work fine, but if I try to add a new page (i.e. ) and fill in data and then go to new page (i.e. jQuery.mobile.changePage("#newPage")), after new page shown, all cloned rows are processed twice (i.e. I guess that the 'create' event is fired twice), the decoration get duplicate, there are 2 div tag for single input field,
i.e. a input tag is decorated to following:
<td style="min-width: 70px;">
<b class="ui-table-cell-label">Price</b>
<div class="ui-input-text ui-body-inherit ui-corner-all ui-state-disabled ui-shadow-inset">
<div class="ui-input-text ui-body-inherit ui-corner-all ui-state-disabled ui-shadow-inset">
<input data-meta-column="TxnGridTxnPrc" disabled="disabled">
</div></div>
</td>
, but original template row looks correct, just cloned rows get duplicates, I also debugged my JavaScript function, after cloned and filled in data and before I go to new page, all things OK (checked DOM tree by Developer Tools of Chrome browser); my program do not fire selectmenu("refresh") or similar calling, the new page is created and loaded by JavaScript, my understanding is, if 'create' event is already fired before I fill data, then cloned rows also get decorations and no need to be decorated again.
, how to avoid it?
There is a screen dump for demo:

Related

Capybara unable to select radio button in data tables

I have a bit of an issue, im trying to select a radio button in a data-tables data. Im able to filter the single data-tables row down to one so it's the only one appearing on the page...but i've tried page.choose, page.find(<xpath>), page.find(<css>), i've also tried doing all the previous within a certain css selection and I can't quite figure out what's left to try.
The relevant HTML is here, unfortunately as this is a work item I can't post everything. however I AM able to click on the label if I specify the id via:
find(:xpath, "//label[#for='approve_row_5']").click however this doesn't actually seem to 'select' the radio button. I've also tried doing a wait after I filter the data-table results
anyways, here is the HTML for the 2 radio buttons after the row has been filtered (the radio buttons reside in a column)
<td class=" align-middle">
<div class="radio">
<input type="radio" name="approve_deny_row_5" id="approve_deny_row_5_approve" value="person_approve" data-ui-verify-key="test_approve" data-ui-verify-title="2017-07-13 14:59:46 -0400">
<label for="approve_deny_row_5_approve">
<span>Approve</span>
</label>
</div>
<div class="radio">
<input type="radio" name="approve_deny_row_5" id="approve_deny_row_5_deny" value="person_deny" data-ui-verify-key="test_deny" data-ui-verify-title="2017-07-13 14:59:46 -0400" data-ui-verify-url="/irrelevant/stuff">
<label for="approve_deny_row_5_deny">
<span>Deny</span>
</label>
</div>
</td>
I thought about just finding the span by the text and clicking it, which passes....but doesn't actually select the radio button. Also I tried searching by the specific value selector as well via a find('input[value="test_approve"]').click but that had no luck either
Any ideas?
Assuming the actual radio inputs are visible on the page (and not hidden to allow for styling) the methods that should work for this are
choose("Approve")
choose("Deny")
or
choose("approve_deny_row_5_approve")
choose("approve_deny_row_5_deny")
If those tell you they can't find the elements then it's most likely the input elements are actually hidden (for styling reasons) and you should be able to use the
choose('Approve', allow_label_click: true)
which will click on the label element associated with the input rather than the input element. That should produce the same result (setting the radio button) unless the behavior you're looking for is based on JS looking for a click on a very specific element (rather than the change event on the input). If that happens to be the case then you need to figure out exactly what element the JS is looking for clicks on, or fix the JS to behave in a more intuitive manner.

How to select items in this custom Vaadin combo box that uses an text input element?

The above pic shows the select list but it's not actually select list, it consist of 'Input' tag, So I tried to set the value using b.text_field.set("argentina") but it only focuses(color changes to yellow) but it's not setting the value, how could I do that?
The code for that select list is given below
<div class="v-filterselect v-widget v-has-width v-filterselect-prompt" role="combobox" style="width: 100%;">
<input tabindex="0" class="v-filterselect-input" id="gwt-uid-17" aria-labelledby="gwt-uid-16" style="width: 100%;" type="text" autocomplete="nope">
<div class="v-filterselect-button" role="button" aria-hidden="true">
</div>
</div>
The problem is that Watir-Classic calls the blur event after setting the value. As a value is not selected from the dropdown, Vaadin considers this as an invalid input and resets it back to "No country selected". You can see the same behaviour when you interact with the combobox manually:
Click the text field
Type "argentina"
Click somewhere else in the page (ie runs the blur event)
To populate the field, you need to select an item from the dropdown. Even though the input field is being cleared, the dropdown does remain (at least when Watir-Classic does it). As a result, we are able to select an item without extra work.
Here is an example using the Vaadin demo page:
require 'watir-classic'
browser = Watir::Browser.new
browser.goto('http://demo.vaadin.com/sampler/#ui/data-input/multiple-value/combo-box')
country = 'ARGENTINA'
browser.text_field(aria_labelledby: 'gwt-uid-16').when_present.set(country)
browser.div(id: 'VAADIN_COMBOBOX_OPTIONLIST').span(text: country).when_present.click
Note that this will not replicate the exact events generated when a user interacts with the field. However, if you are just using the control, rather than testing the field (ie a Vaadin developer), this is likely sufficient.

Jquery Mobile Javascript not working on ajax load

Have the following markup in my html page to toggle a search bar based on if a search icon is clicked:
<a id="searchIcon" href="/"></a>
<div id="searchWrapOuter" style="display:none;">
<div id="searchWrapInner">
<div id="formContainer">
<form id="searchForm" action="#">
<div>
<input type="search" name="search-mini" id="search-mini" value="" data-mini="true" />
</div>
</form>
</div>
</div>
</div>
Width the following javascipt/jquery:
$(function() {
$(document).on("click", "#searchIcon", function () {
var searchWrapper = $("#searchWrapOuter");
$(searchWrapper).slideToggle();
return false;
});
});
This code works as expected on a page load direct off a Url. When coming into the page off a link which is Ajax loaded, loads the contents of the page into the DOM, and the DOM ready handler only executes for the first page.
I have read about using the
$(document).on('pageinit'), not $(document).ready()/$(function()
I still haven't been able to get this to work when coming in off an ajax link however. What would be the correct way to implement these events to get the code to work coming in from an Ajax link?
Thanks,
Most likely it is because you are using IDs instead of classes. jQuery Mobile doesn't work well with IDs because it caches pages into the DOM so if you open a page, close it, then go back to the page, you might have your page twice inside the DOM (one visible, one hidden/cached). So when you do $("#searchWrapOuter") you don't know which element you are actually dealing with (in your case, probably the hidden one).
The solution is to change your IDs to classes. This is not very intuitive but I found that is the best way to work with jQuery Mobile.
Also note this comment in the doc which might also be relevant to you:
The id attribute of all your elements must be not only unique on a given page, but also unique across the pages in a site. This is because jQuery Mobile's single-page navigation model allows many different "pages" to be present in the DOM at the same time. This also applies when using a multi-page template, since all "pages" on the template are loaded at once.
http://jquerymobile.com/demos/1.2.0/docs/pages/page-anatomy.html
You can manually adjust delay time to 500ms and 1s.
$(searchWrapper).delay(1000).slideToggle();
My issue is that the page id was below the pages tags. So once I moved the page div above it, the javascript was included in the ajax page load. Previous to this

Knockout, JQMobile, and generating a collapsible-set doesn't quite seem to work right

I've checked out a number of samples, but none are quite the same as what I'm trying to do.
What I've got works, mostly, but it doesn't quite work right.
Here's a fiddle to illustrate the issue.
http://jsfiddle.net/5yA6G/4/
Notice that the top set works fine, but it's statically defined.
The bottom set (Tom, steve, bob) "work" basically, but the header element ends up both in the collapsible header AND in the portion of the collapsible that gets hidden.
Seems like I must be doing something wrong, but I haven't been able to figure out what.
Any ideas?
Just for reference and for anyone else running into this problem, it turns out to be at least somewhat obvious in hindsight.
Knockout's built in "anonymous" templating works great in many cases, but with JQMobile, it can be a tad quirky.
That's because JQMobile will adjust the content of the anonymous template when the page loads, just as it does with all the other content.
Then, later, when you use knockout's ApplyBindings function, knockout will add the applicable elements, just as it should. As many posts and answers have hinted at, you then MUST call collapsible() on the newly created elements, via something like this.
$("div[data-role='collapsible']").collapsible({refresh: true});
No problem there. HOWEVER, if JQM has already applied formatting, then the anonymous template has already been "rendered" by JQM, so rendering it again by calling collapsible causing all sorts of funky results, including doubled heading, nested collapsibles, etc.
The solution for me was to use Knockout's "Named Template" feature, and just put the template to render the collapsible elements into a tag, like this:
<script type="text/html" id="alarm-template">
<div data-role="collapsible" data-collapsed="true" data-collapsed-icon="arrow-d" data-expanded-icon="arrow-u" data-enhance="false">
<h3 data-bind="text:name"></h3>
<p>The content here</p>
<p data-bind="text: name"></p>
</div>
</script>
Doing this prevents JQM from "rendering" the template elements when the page loads, so they'll be rendered properly when they're actually generated.
EDIT: The above works fine for collapsibles NOT in a collapsible-set, but, if they're in a set, I've found the styling of the elements (particularly, the corner rounding to indicate belonging to a set) doesn't work right.
From what I can tell, there are 2 problems:
The first is that just triggering "Create" doesn't actually refresh the styling of all the collapsibles in the set. to do that you have to do...
$("div[data-role='collapsible-set']").collapsibleset('refresh');
But, there's a worse problem. JQM "marks" the last item in the set as the "last item". That fact then gets used to determine how to style the last item as it's being expanded/collapsed.
Since Knockout doesn't actually rebuild the entire set (for speed), each time you call the refresh method, JQM dutifully marks the last item as "last", but never removes the marks on previous items. As a result, if you start from an empty list, EVERY item ends up being marked "last" and the styling fails because of this.
I've detailed the fix for that at github in an issue report.
https://github.com/jquery/jquery-mobile/issues/4645
I actually found a much easier way to do this:
Set up your foreach binding as you normally would for me it looked like this
<div data-bind="foreach: promotions">
<h3 data-bind="text: Title"></h3>
<p>Creator:<span data-bind="text: Creator"></span></p>
<p>Effective Date:<span data-bind="text: EffectiveDate"></span></p>
<span data-bind="text: Description"></span>
<a data-bind="text: ButtonText, attr: {href: ButtonLink}"></a>
Wrap that in a div with class="collapsible like so
<div data-role="collapsible-set" data-bind="foreach: promotions">
<div class="collapsible">
<h3 data-bind="text: Title"></h3>
<p>Creator:<span data-bind="text: Creator"></span></p>
<p>Effective Date:<span data-bind="text: EffectiveDate"></span></p>
<span data-bind="text: Description"></span>
<a data-bind="text: ButtonText, attr: {href: ButtonLink}"></a>
Apply the collapsible widget via jquery mobile after you do your binding like so:
$(document).ready(function () {
ko.mapping.fromJS(data, dataMappingOptions, PromotionViewModel.promotions);
ko.applyBindings(PromotionViewModel);
$('.collapsible').collapsible();
});
For a collapsible set the same idea can be applied just set the class="collapsible-set" on your foreach div. Hope this helps

getting the values of tds using jquery

I am using jquery 1.6.4 and I have a table. Initially in the table, a user is presented by only one row and a few columns. I, then, let users add as many rows as they would like using by doing this
$('.add').live('click', function(e){
e.preventDefault();
var $parentRow = $(this).parents('tr');
$parentRow.clone().insertAfter($parentRow);
$parentRow.next().find('input').val('');
$(this).replaceWith('-');
});
I also let them delete the rows on fly doing this
$('.delete').live('click', function(e){
alert("removing");
e.preventDefault();
$(this).parents('tr').remove();
});
However now I want the values that they are entering in these columns to be collected. I am not sure how to collect those values when they hit submit button as in my view source all I see is this
<tr>
<td class="actions">+</td>
<td><input type="text"></input></td>
<td><input type="text"></input></td>
<td><input type="text"></input></td>
<td><textarea rows="1"></textarea></td>
</tr>
In the page source it shows only one row where as in my view I definitely see three rows added. Not sure what am I missing and how to get the values
You don't have ids so it will be difficult to tell what you are actually collecting, but to get the values of the inputs, both static and dynamic, you can use this:
//submit code
$('input[type=submit]').click(function(){
$('table input').each(function(index,item){
//for testing you could just output to a div
//$('#output').append($(this).val());
});
});
From what I can tell, your input fields don't have names, so you're not going to get much when submit is pressed.
Also, you won't see DOM updates in your view source. View source will only show you what the page looked like when it first loaded.
To get a live view of the page, you can either use FireBug, for FireFox, or if you're using Google Chrome, there are developer tools under the "View" menu that you can use to see how the html looks live.

Resources