I'm trying to generate the following code with HAML within a .each loop. Depending on the true/false condition within the loop, it should either create a new div1 with a div2 or append div2 within the previous div1. This is a simplification of the logic:
Desired output:
if true, append `div2` within `div1`,
<div class="div1"> #added by true condition
div1 text
<div class="div2"> #added by true condition
div2 text
</div>
<div class="div2"> #added by false condition
div2 text
</div>
<div class="div2"> #added by false condition
div2 text
</div>
</div>
else, create a new `div1` and add `div2` within it
<div class="div1"> #added by true condition
div1 text
<div class="div2"> #added by true condition
div2 text
</div>
</div>
<div class="div1"> #new div1, added by true condition
div1 text
<div class="div2"> #added by true condition
div2 text
</div>
</div>
Effectively, I'm trying to do this
//within a loop logic
- if condition == true
.div1
div1 text
-# in all conditions
.div2
div2 text
This is my HAML logic, I was using tab_up but I don't think that's the correct HAML method:
//within a loop logic
- if condition == true
.div1
div1 text
- tab_up(2) #trying to indent the HAML, not just the HTML output
.div2
div2 text
The way to do things like this in Haml is to organise your data before tying to convert it to HTML. The methods of Enumerable can help here.
The way you’ve described the problem, splitting your enumerable with slice_before looks like the most direct solution – you want to open a new div1 before every item where the condition is true (here I’m assuming that the condition depends on the item). Possibly something like this:
- items.slice_before {|item| determine_condition(item) }.each do |div1_block|
.div1
div1 text
- div1_block.each do |item|
.div2
div2 text
Depending on what you’re actually trying to do, there may be a better way to organise your data – the way it is described here suggests you are looking at it at a lower level than needed because you are already thinking in terms of iterating and creating the HTML as you go.
The basic idea would be to get an array (or Enumerator) of arrays, with each inner array representing the contents of a div1. The Haml then falls out pretty easily. chunk, each_slice and group_by are some Enumerable methods that might be worth looking at.
Related
I have a requirement to verify field name and values. My code looks like
<div class="line info">
<div class="unit labelInfo TextMdB">
Reference #:
</div>
<div class="unit lastUnit">
701
</div>
</div>
</div>
<div class="line info">
<div class="unit labelInfo TextMdB">
Registered Date:
</div>
<div class="unit lastUnit">
05/05/2020
</div>
</div>
I gave my xpath as
"//div[#class='unit lastUnit']//preceding-sibling::div[#class='unit labelInfo TextMdB' and contains(text(),'Reference #:')]".
With this xpath I am able to reach "reference#" field . But how to verify reference # field is displaying the value (in this case 701) .
Appreciate your response.
Thanks
You can first reach the Reference # text by using its text in the xpath and then you can use following-sibling to fetch the div tag and then use getText()(java) / text (python) method to get 701.
(Edited answer after OP's comment)
If you want to check if the element is displayed on the page or not then you can fetch its list and check if the size of that list is greater than 0 or not.
You can do it like:
In Java:
List<WebElement> elementList = driver.findElements(By.xpath("//div[#class='line info']//div[contains(text(),'Reference #')]//following-sibling::div"));
if(elementList.size()>0){
// Element is present on the UI
// Finding its text
String text = elementList.get(0).getText();
}
In python:
elementList = driver.find_elements_by_xpath("//div[#class='line info']//div[contains(text(),'Reference #')]//following-sibling::div")
if (elementList.len>0):
# Element is present
# Printing its text
print(elementList[0].text)
I have v-for loop where I iterate over some clients and display some data. Inside this loop I have an element that needs to be styled initially based on the client data but on click this has to be toggled between true of false.
<div v-for='client in clients'>
<span class='heart margin-right-10'>
<i v-bind:class='[client.favourite?"fas fa-heart fa-lg hearted":"fal fa-heart fa-lg"]' v-on:click='change()'></i>
</span>
</div>
So initially client.favourite has a value of true, and on click this needs to be toggled between true or false.
How should I approach this so I can toggle between the two classes?
Well, if I understand your goal I will try with something as simple as possible like:
change() {
client.favourite = !client.favourite;
}
I'm using Algolia instantsearch.js for search, and to display my result page, I'm using Bootstrap 3, and I'd like hits to be displayed in 3 columns:
qry | hit1 | hit2
| hit3 | hit4
| hit5 | hit6
(where qry = the search query input widget)
etc..
If it's mobile, it should display as:
qry
hit1
hit2
hit3
etc.
Can someone help me with the html/css I can use to implement this?
Thanks!
Basically, you want to use bootstrap rows and grid layout col-{xs,sm,md,lg}-X (More info about the grid layout here).
One interesting property with bootstrap is that if you declare a block as being col-YY-X, if the screen width is under the dimensions YY is associated with, it automatically expands to the full width.
instantsearch.js's widgets expose a cssClasses parameter that allows you to customize the classes of the underlying markup.
To easily do two columns, all you need to do is declare the root element of the cssClasses as being a .row, and each result as a .col-sm-6 (or .col-md-6 or .col-lg-6 depending on which screen size you want it to apply).
By combining them, you can have some really interesting layouts.
See this JSFiddle
Here, I've extended a bit the idea. Try to resize the view, and you'll see that it automatically picks a number of results to display per line depending on the width by combining multiple col-YY-X classes on the hit widget.
search.addWidget(
instantsearch.widgets.hits({
container: '#hits',
templates: {
empty: 'No results',
item: '<div class="hit">{{title}}</div>'
},
hitsPerPage: 6,
cssClasses: {
root: 'row',
item: 'col-lg-3 col-md-4 col-sm-6'
}
})
);
As you can see, I've also added an inner class to the item template to be able to use the item as a wrapper with padding inside to avoid having the hits glued to each other. I apply the border to the inner element, because adding margins to bootstrap grid elements is not the right solution.
The layout itself is really simple, you can just nest rows together:
<div class="container-fluid">
<div id="search" class="row">
<div class="col-sm-4">
<div id="input"></div>
</div>
<div class="col-sm-8">
<div id="hits" class="row">
</div>
</div>
</div>
</div>
Is there any way to generate many divs nested each other?
I expect print some like this:
<div>
<div>
<div>
<div>
<div>
</div>
</div>
</div>
</div>
</div>
Simple loop is not helping
- (1..5).each do |i|
%div
Goes to
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
There isn't any way of doing this in pure haml, by design.
Firstly, ask yourself: Do you really need this? There are often far better ways to achieve the result you want.
In my case, I needed an arbitrary nesting of divs with a particular class, based on a number I was given externally. I added the following to my rails helpers:
def nestify(css_class, level, &block)
if level > 0
content_tag(:div, class: css_class) { nestify(css_class, level - 1, &block) }
else
yield
""
end
end
Then, in your haml, you use it with a block:
= nestify('each-div-has-this-class', 5) do
Content for inner div.
[Edit] Quick note: I wrote this a while back, can't remember why - but this code is not production ready. Ruby doesn't work well with recursive functions. Please flatten it into a loop for better performance / scalability.
I'll try to keep it simple.
I have a list of similar rows like this:
HTML code:
<li ...>
<div ... >
<some elements here>
</div>
<input id="121099" class="containerMultiSelect" type="checkbox" value="121099" name="NodeIds">
<a ...>
<div ... />
<div ... >
<h2>Identified Text</h2>
<h3>...</h3>
</div>
</a>
</li>
I want to click the checkbox with a certain text, but I can't use any of its elements, because they are the same for all the list, and id is generated automatically. The only thing can be differentiated is the h2 text. I tried :
browser.h2(:text => /Identified/).checkbox(:name => "NodeIds").set
and I got UnknownException which is obvious because checkbox is not nested with a tag.
What can I do in this case?
Thanks
The h2 and checkbox are related by the li, which is a common ancestor. Therefore, to find the checkbox, you can look for the li that contains the h2 element. I find the most readable approach to doing this is by using the find method of the element collection. The find method basically allows you to make custom locators.
The code would be:
parent_li = browser.lis.find do |li|
li.h2(:text => 'Identified Text').present?
end
parent_li.checkbox.set
Notes:
browser.lis creates a collection of all li elements.
find iterates through the lis and returns the first element that has the block evaluate as true - ie the first li where an h2 with the specified text is present.
First have a look at this explanation
http://jkotests.wordpress.com/2012/12/20/finding-a-parent-element-that-matches-a-specific-criteria/
Now following a similar approach,
First locate the element that has a unique identifier
parent=#browser.h2(:text=>"Identified Text")
Now we have to iterate over to the parent element which contains both the checkbox and text against it.
parent=parent.parent until parent.tag_name=="li"
Once the control is on the li element, simple click on the checkbox using.
parent.checkbox.click