Control with Selenium a dynamic table created with javascript with Selenium - javascript

I would like to know if it would be possible to select the menu item from one created almost entirely with javascrip with selenium. As html tags for this table are only available in view source
<table id = "table_id"> <tr> <td> <script> *** </script> </td> </tr> </table>
and instead of asterisks there is a javascript that dynamically creates this menu with
with (milonic = new menuname ('menu_name'))
and aI () strings. When you click on a menu item, a submenu opens. My question - how can i for example select item no.2 from the menu and then item no.3 from the submenu? Such a construction as
driver.find_element_by_id ('table_id').click ()
does not help, only the menu item in the middle is selected, but not clicked.

Ok i got solution, i used F12 in FF and found all the links i needed. The instability can be solved with this code:
wait = WebDriverWait (driver, 10)
wait.until (EC.element_to_be_clickable ((By.ID, "id"))). click ()

Related

Retain state of multi-level navbar/sidebar on new page

I'm very new to programming & working on creating a website for a work project.
In it, there will be a multi-level (w/sub-menus) vertical sidebar on each page.
The problem I'm facing is that every time a user clicks on one link, the sidebar resets to its original state & will have to redo the same thing & not very UX friendly.
I took the template of the accordian sidebar from here.
I've looked at various search results on both stack overflow & google, but can't seem to understand how to get it working to retain the state of the sidebar, regardless of how many levels are opened.
Can someone please help me with the JS code to get it working?
UPDATE:
Nathan, thanks for writing mate! I really appreciate the help.
So based on your suggestion, I've written the following (shoddy) code that injects the 'checked' attribute to the input element.
But it isn't transferring over to the new/redirected html page when a user clicks on one of the sub-menus. What am I missing here?
var menuIndex = -1;
//extract all the input elements
var inputs = document.querySelectorAll('.parent-menu');
//Find index of the element from the array that has "checked == true"
function indexFinder() {
for (var i = 0; i < inputs.length; i++) {
if (inputs[i].checked == true) {
menuIndex = i;
console.log(menuIndex);
}
};
}
//Function to set/inject the attribute
function attributeSetter() {
inputs[menuIndex].setAttribute('checked', 'checked')
}
//When a user clicks literally anywhere, it'll run the indexFinder function
//to check if any of the input elements were expanded (i.e. checked == true)
window.addEventListener('click', () => {
indexFinder();
});
//Run the attributeSetter function when a page loads
window.addEventListener('DOMContentLoaded', () => {
attributeSetter();
});
Welcome to the world of programming! Hopefully I can help you out a little!
So what you're asking is something that can easily get a little complicated.
In order to achieve what you're trying to do you need to specify how you want your menu to look on each individual page!
Allow me to present a few menu options for an imaginary site:
Home
Contact
Email
Mail
About
The Company
Our Owner
I've indented the page names based on how we want them to show up in our menu.
So for example you may click on "Contact" and it drops down with the Email and Mail options.
Well, if you take your regular code from that webpage and copy and paste it everywhere. Any time you reload a page (or travel to another page with the same code) it's gonna reset the code! Thus "closing" the menu. Think of it as some sort of multi-dimentional sci-fi. When you load a webpage, you are accessing the main flow of time, any time you make an update to that page it takes you to an alternate reality with that change! but once you reload the webpage you jump back to the main timeline as if you never made that change (when you get into more advanced web dev, this analogy will break down but it should work to help your understanding for now.)
So let's say I click on the Contact > Email option and it takes me to the Email page. Well, in order to make it seem like my changes to the menu bar (clicking "Contact" to expand the dropdown) are still active. I need to hardcode the change into the Email page!
Here's some sample code:
<nav class="nav">
<a class="navOption">Home<a>
<a class="navOption">Contact<a>
<div class="navDropdown">
<a class="navOption">Email<a>
<a class="navOption">Mail<a>
</div>
<a class="navOption">About<a>
<div class="navDropdown">
<a class="navOption">The Company<a>
<a class="navOption">Our Owner<a>
</div>
<nav>
By default the .navDropdown will be closed. However when we add a class to them .active they will expand! If this is my base menu, then how should I make it so that the "About" dropdown is expanded when you are on one of the About pages?
Simply by adding .active to that dropdown!
<nav class="nav">
<a class="navOption">Home<a>
<a class="navOption">Contact<a>
<div class="navDropdown">
<a class="navOption">Email<a>
<a class="navOption">Mail<a>
</div>
<a class="navOption active">About<a>
<div class="navDropdown">
<a class="navOption">The Company<a>
<a class="navOption">Our Owner<a>
</div>
<nav>
Now, my example is different from yours because it's meant more for JavaScript. However, you can use the same concept in your code too.
For you, instead of having a .active class to expand a dropdown menu. You are using a checkbox element! In your codem you have CSS which is checking to see if the checkbox is checked and then it is opening the dropdown menu if it is:
<input class="cd-accordion__input" type="checkbox" name ="group-1" id="group-1">
So, if we use this method on our example webpage. We could set it to be open by setting the checkbox to start out being checked. Like so:
<input class="cd-accordion__input" type="checkbox" name ="group-1" id="group-1" checked>
It's important to note that as you get better and better at web development (eventually learning JavaScript and a server side language such as PHP). You will be able to piece together more advanced methods to doing what we're trying to accomplish! But for now, I hope I was able to break this down for you!

Display the selected/active link in a div using jQuery

I have a simple html menu, when a menu item is clicked a class of `mg_cats_selected" is added to the anchor tag (which is the menu item).
I would like to copy the text value of the active/selected anchor tag and display it in another div on the page, but I would like to only display it once. When a new item link is clicked, I want to remove the old value from the separate div that I've created it and display the new value of the new selected menu item.
I hope that makes sense.
This is the HTML menu
<div id="mgf_165" class="mg_filter mg_new_filters">
<a rel="163" id="163" class="mgf_id_163 mgf mg_cats_selected left_menu" href="javascript:void(0)">Bathrooms Sinks</a>
<a id="164" rel="164" class="mgf_id_164 mgf left_menu" href="javascript:void(0)">Bowed</a>
</div>
This is the jQuery and the div where I wanna display the text values.
<script type="text/javascript">
jQuery(document).ready(function(){
console.log('test');
jQuery("a.left_menu").click(function(){
var txt = jQuery("a.left_menu").text();
//$(this).attr('rel');
jQuery("#category").append(txt);
});
});
</script>
<div id="category">
</div>
At the moment when I click on, say, "Bowed", this displays in the div
Bathrooms SinksBowed
And if I click again on "Bathroom Sinks", the same thing repeats
Bathrooms SinksBowedBathrooms SinksBowed
How can I deal with that? And did I follow the correct logic here?
You are currently getting the text of all the menu items and then appending it to the div.
You need to get the text of the clicked menu item, and then set the content of the div to the text value of that menu item.
jQuery(this) // the clicked menu item
jQuery('#category').text('VALUE') // set the text content of the tag to VALUE
Working solution on JSFiddle..
See Inside the Event Handling Function to learn more about jQuery event handling.

Javascript code works in console but not HTML (Click Function)

document.getElementById('hello').click();
The above code works when inserted into the google chrome console - It displays the dropdown of 'hello' - What I'm trying to do is open up a dropdown when I click a whole table row, using the following code
<tr onclick="document.getElementById('hello').click();">
Here is the dropdown I'm trying to activate
<a href="#" id="hello" data-toggle="dropdown" class="btn dropdown-toggle"><i class="icon-cog">
Infact I do see the button being clicked when I click the row, but the dropdown does not toggle. Whats the best way to toggle the dropdown (The dropdown works if I simply click it, I'm trying to toggle it using javascript)
Thanks!
Try like:
<tr onclick='$("#hello").trigger("click");'></tr>
I am not sure about scenario, but this is what I came up with. Please note that I have changed tr to p for the demo. Change it back to suit your needs.
var helloID = document.getElementById("hello");
function initDropdown() {
helloID.click();
}
helloID.addEventListener("click", function(evt) {
alert ("Click triggered on ID : " + evt.target.id);
});
<p onclick="initDropdown();">Click Me</p>
<script src="http://code.jquery.com/jquery-1.11.2.min.js"></script>
<tr onclick="$('#hello').click();">

How to access (enhanced-) grid cell data from a cell context menu?

my web application is based on dojo 1.6.0.
The problem that I have is based on event handlers basically and/or their utilization
in dojos "dojox.grid.EnhancedGrid" library.
My application contains a dojox Enhanced Grid with a great number of rows. (100+)
This Enhanced Grid makes use of the "cellMenu"-Plugin to show a context menu
for each Grid Cell on right click.
My goal is to use the context menu for "smart" selection of rows.
For example:
The user right clicks on a cell wich is positioned in the column "lastname" and has the value "miller". He then clicks "smart select" in the context menu.
The application will then loop over the row data and select all rows wich have "miller" as "lastname".
In the aftermath the user will innitiate actions with the selected rows through press of a button.
Here is a small sourcecode example illustrating the declarative approach for visualization of the Enhanced Grid with Context Menu:
<table dojoType="dojox.grid.EnhancedGrid" plugins="{cellMenu:'myMenu'}">
<div id="myMenu" dojoType="dijit.Menu">
<div id="mi1" dojoType="dijit.MenuItem">Do something with this cell</div>
<div id="mi2" dojoType="dijit.MenuItem">Do something else with this cell</div>
</div>
<thead>
definition of columns
</thead>
</table>
Action code is handled separate from the visualization in js-Files:
<script type="text/javascript">
dojo.addOnLoad(function(){
dojo.connect(dijit.byId('mi1'),'onClick',function(event){
//Use Data from the cell clicked to do something
});
dojo.connect(dijit.byId('mi2'),'onClick',function(event){
//Use Data from the cell clicked to do something else
});
});
</script>
I am relatively new to dojo and do not have experience with the handling of the EnhancedGrid.
So my problem is the following:
When I click inside the context-menu which is a "dijit.Menu" the "onClick" event
of the "dijit.MenuItem" contained therein is triggered.
Inside this event handler I need to read the contents of the "Grid Cell" the context menu
was opened on, but I do not have (or do not currently know) a way to get a reference to the "Grid Cell".
With default tactics I might be able to get a reference to the MenuItem and from there maybe to the Menu, but I was unable to find an attribute containing the reference to the "Grid Cell" or a row/column ID that would enable me to access the Cell clicked.
Since context menus are there to do something with the "item" they were opened with by right clicking I think that there has to be a way (as meant by the designer) to access this "item".
I have not yet found a documentation or example illustrating this and would appreciate all your help.
Here is a possible sollution (maybe not the best there is) for using a context menu on a dojo grid for selection purposes:
Visual Part (Declarative)
<table id="grid" dojoType="dojox.grid.EnhancedGrid"
plugins="{indirectSelection:true,menus:{cellMenu:'GridCellMenu'}}">
<div dojoType="dijit.Menu" id="GridCellMenu" style="display:none;">
<div dojoType="dijit.MenuItem" id="mi_selectSimilar">select similar items</div>
<div dojoType="dijit.MenuItem" id="mi_deSelectSimilar">DEselect similar items</div>
</div>
<thead>
<tr>
<th field="id">ID</th>
<th field="lastname">Lastname</th>
<th field="firstname>firstname</th>
</tr>
</thead>
</table>
JavaScript Background
// Stylesheets and Dojo Groundwork are neglected in this example
<script type="text/javascript">
dojo.require('dijit.Menu');
dojo.require('dijit.MenuItem');
dojo.require('dojox.grid.EnhancedGrid');
dojo.require('dojox.grid.enhanced.plugins.IndirectSelection');
dojo.require('dojox.grid.enhanced.plugins.Menu');
var currentEvent = null;
var fn_selectSimilar = function(){
var data = currentCell.grid.store.objectStore.data;
dojo.forEach(data,function(row,idx){
if(row[currentEvent.cell.field] == data[currentEvent.rowIndex][currentEvent.cell.field]){
currentEvent.cell.grid.selection.addToSelection(idx);
}
}
}
var fn_deSelectSimilar = function(){
var data = currentEvent.cell.grid.store.objectStore.data;
dojo.forEach(data,function(row,idx){
if(row[currentEvent.cell.field] == data[currentEvent.rowIndex][currentEvent.cell.field]){
currentEvent.cell.grid.selection.deselect(idx);
}
}
}
dojo.addOnLoad(function(){
dojo.connect(dijit.byId('grid'),"onCellContextMenu",function(e){
currentEvent = e;
});
dojo.connect(dijit.byId('mi_selectSimilar'),"onClick",fn_selectSimilar);
dojo.connect(dijit.byId('mi_deSelectSimilar'),"onClick",fn_deSelectSimilar);
});
</script>
This will go through all the selected items in the grid and get the value of the cell named "YourGridColumnName".
var items = YourDataGridId.selection.getSelected();
if (items.length) {
dojo.forEach(items, function(selectedItem) {
alert(YourDataGridId.store.getValues(selectedItem, "YourGridColumnName"));
})
}
Hope it helps.
You can link an event handler into the mouse and keyboard events that will bring up the context menu. The event has a row index that you can store in a place where the menu item will find it.

use JQuery to find the collective radio button group name

I've asked a lot of jQuery questions recently as I'm trying to use it rather good old Javascript, as I mentioned in previous questions, "I'm currently having to extend an very old ASP.NET site which has a database generated front end and is a behemoth of an application, it needs completely rewriting - however I've been told to add to it than redevelop it "
Now what I'm doing is once the backend is rendering a table to the interface I wish to loop through the tr elements of the table, within one of the td elements of the tr there are two radio buttons. I need to determine the name of the radio button group as I don't define them, the systems does using a GUID or something?
This is the table for example...
<table id="tableID">
<tr>
<td class="qCol">
<!-- Label here -->
</td>
<td class="qCo2">
<!-- img here -->
<!-- and a text box -->
</td>
<td class="qCo3">
<!-- select menu here -->
</td>
<td class="qCo4">
<!-- radio buttons here -->
</td>
<td class="qCo5">
<!-- select menu here -->
</td>
<td class="qCo6">
<!-- hidden validation image here -->
</td>
<tr>
</table>
Okay, I'm looping through the table and at the same time switching the innerHTML of one cell to another and hiding some of the rows, I'll be adding functionality to show these later, here's the jQuery:
$('#tableID tr').each(function (i) {
/*switch select and validation and clear */
$(this).children('td.qCol').html($(this).children('td.aCol5').html());
$(this).children('td.aCol5').html($(this).children('td.vCol'.html(""));
/* hide all but the first row*/
if (i >= 1) {
$(this).hide();
}
now I'm trying to determine the name attribute of the radio buttons that will be in the cell with class .qCo4, however I'm having no luck as the following returns an error and is "undefined"...
/* get the radio button name and check if either are selected*/
// check something exists...
if ($('input:radio', this).attr('name')) {
var thisRadioName = $(this).closest("input:radio").attr('name').val();
alert(thisRadioName);
}
$this is the tr element, so should I be using child rather than closest? If this makes no sense I can expand and explain better.
you should use find() or children(). closest() goes up the tree, while find looks for elements down the tree
var thisRadioName = $(this).find("input:radio").attr('name');
you can use also ':checked' to check if any radio is checked
var checkedRadio = $(this).find("input:radio:checked")
You should use children if you are absolutely sure that the elements you are looking for are direct child of the element, otherwise use find(). (using finds protect you from refactoring code if you modify the html, like adding a wrapping div for other reasons like styiling)
look at this fiddle: http://jsfiddle.net/nicolapeluchetti/Evq6y/
var thisRadioName = $(this).find("input:radio").attr('name');
should do what you want

Categories

Resources