iterate over chunks of an array using ng-repeat - css

My controller grabs people from the server:
$scope.people = [person1, person2, person3, person4, person5,...]
My template needs to display three people per line. For example if it was a table:
<table>
<tr>
<td>person1</td><td>person2</td><td>person3</td>
</tr>
<tr>
<td>person4</td><td>person5</td><td>person6</td>
</tr>
</table>
I wasn't sure how to conditionally apply the <tr> when $index % 3 == 0 or what the best practices are. I know how to do this by adding grouping logic to the controller but I thought it would be best to keep design logic out of the controller.

There isn't an existing way to do what you are saying with a table. The easiest way to do what you want is to use divs with fixed widths, so that they will auto-wrap after three.
Here is an example:
HTML
<div ng-app="app">
<div ng-controller="TableCtrl" class="my-table">
<span ng-repeat="person in people" class="person">{{person}}</span>
</div>
</div>
CSS
.my-table{
width: 400px;
height: 400px;
border: 1px solid black;
}
.person{
width: 100px;
display: inline-block;
white-space: nowrap;
border: 1px solid black;
}
JavaScript
var app = angular.module('app',[]);
app.controller('TableCtrl', function($scope){
$scope.people = ['Aaron', 'Abraham', 'Adam', 'Aristotel', 'Aziel', 'Azod', 'Azood'];
});
Working copy: http://jsfiddle.net/ZX43D/

After years of angular experience, It's obvious that the best way to do this is to split the array into chunks in the controller. Each time the original array is modified, update the chunked array.

Here is my current solution (It's O(N^2) so doesn't scale for large lists).
Template:
<div ng-app="myapp">
<div ng-controller="testing">
<div ng-repeat="_ in items">
<span ng-show="($parent.$index % 3 == 0) && ($parent.$index + 3 > $index) && ($parent.$index <= $index)" ng-repeat="item in items">
<span ng-show="1">
{{item}}
</span>
</span>
</div>
</div>
</div>
Controller:
angular.module('myapp', []);
function testing($scope){
$scope.items = ['a', 'b', 'c', 'd','e','f','g'];
}
Result:
a b c
d e f
g
Fiddle:
http://jsfiddle.net/LjX3m/
Conclusion:
I'll probably try use CSS for this as #aaronfrost mentions. (However it may not be possible since some wrapping divs may be required for each chunk).

Related

Understanding of CSS: Position

I have a question about the CSS property: Position
As I was creating a page that looks this:
As you can see, there is a table and div next to each other. The following codes shows that how I achieve this:
Code Structure:
<div className="daily-task-view">
<table{...getTableProps()}>
<thead >
{headerGroups.map(headerGroup => (
<tr className="table-header-row"{...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th {...column.getHeaderProps(column.getSortByToggleProps())} className={
column.isSorted
? column.isSortedDesc
? "sort-desc"
: "sort-asc"
: ""
} ><h5 className="table-header-head"><b>{column.render("Header")}
</b></h5></th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{page.map((row, i) => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return <td className="table-content" {...cell.getCellProps()}>{cell.render("Cell")}</td>;
})}
</tr>
);
})}
</tbody>
</table>
<div className="search">
<GlobalFilter filter={globalFilter} setFilter={setGlobalFilter}/>
<Button variant="success" className="button-to-add-dailytask">Add Daily Task</Button>
</div>
</div>
CSS:
.search{
margin-left:200px;
border-radius: 20px;
background-color: white;
width:fit-content;
position: absolute;
top: 10px;
left: 780px;
}
.daily-task-view{
padding-top: 10px;
padding-left: 20px;
position: relative;}
So far, the CSS that I have did presented the view that I want BUT when I Zoom In or Zoom Out, The Search which is the div tag didn't follow the action like moving the same way as the table been moving instead it didn't move and stick at that position that I set.
As I want the table and div be together so that that can act the same way (such as Zoom in/Zoom out)
What can I do, I used Absolute and Relative. Based on my understanding, both need to be together but in my case, it doesn't act that way.
Is my understanding of these 2 properties wrong?
Please Help
In your code now, you have the .search div inside the .daily-task-view one. This might be the issue
Here is an example of how you could achieve what I think you have in mind, by using a wrapper div and giving that display: flex, and then making .daily-task-view + .search separate and not .search inside the other. In my example I have also set widths for the div's, but it could be fit-content as well, or what you prefer.
https://codepen.io/akmalmo/pen/BapeXra
HTML
<div class="wrapper"><div class="daily-task-view">
Table
</div>
<div class="search">
Search
</div>
</div>
CSS
.wrapper{display:flex}
.search{
border-radius: 20px;
width:40%;background:red;
margin-left:20px;}
.daily-task-view{
padding-top: 10px;width:60%;background:blue;}
.daily-task-view, .search{padding:20px;}
Does this help?

CSS Columns works with all browsers except Firefox

I can't seem to get Firefox to cooperate with my 3 columns. It works with all the other browsers. Please have a look at http://www.usslittlerock.org/Marines_Workpage.html. I stripped everything off the page except the relevant CSS and HTML. I've worked with columns before with no problems but this time I used tables in the mix. The look of the layout needs to remain the same. I would actually prefer to eliminate the TABLES but I don't know how to keep the layout style with CSS alone. I've tried a number of different solutions from this site but none work. Thanks for any suggestions you can give.
http://caniuse.com/#search=column-gap reports, under known issues:
Firefox does not split tables into columns
Sorry.
Good new, you can keep you code mostly intact, but replace everything with div's. (this is the easiest way for me to explain it):
With your favorite editor do some simple text replace:
<table> --> <div class="table">
<th> --> <div class="th">
<tr> --> <div class="tr">
<td> --> <div class="td">
<tbody> --> <div class="tbody">
... and the equivalent </table> --> </div>, etc.
Change your CSS:
.marines table --> .marines div.table
.marines table th --> .marines div.th
.marines table td --> .marines div.td
Add a few new bits to your existing css:
.marines div.td {
....
display: inline-block;
width: 52%;
}
.marines div.th {
....
display: inline-block;
width: 52%;
}
.marines div.td:nth-of-type(2) {
width: 20%;
}
.marines div.td:nth-of-type(3) {
width: 25%;
}
and it will work in all browsers (This isn't a complete answer -- you'll still need to handle the Bold text in the headings and the index-Letters, but I think you get the idea.)

How to only select a displayed element using CSS

In my program, I have a text element that displays in 2 different sections. It will display is section A, and again in section B (popup). I was hoping to create 1 object using CSS that could be used for both sections. That way I could call the same object to check this element regardless of where it is displayed. I can't seem to figure it out. Maybe its not possible, or maybe I need someone who has more experience with HTML and CSS to show me the light.
Here is the HTML for this element in section A when it is displayed
<td id="treeCol" valign="top" style="overflow: hidden; display: block;">
<div id="orgTreeAndSearch">
<div class="orgSelection">
<span id="selection" class="" title="Select an org unit">Select an org unit</span>
Here is the HTML for this element in section A when it is NOT displayed (hidden when section B is displayed)
<td id="treeCol" valign="top" style="overflow: hidden; display: none;">
<div id="orgTreeAndSearch">
<div class="orgSelection">
<span id="selection" class="" title="Select an org unit">Select an org unit</span>
Here is the HTML for this element in section B when it is displayed
<div class="blockUI blockMsg blockPage PopUp White" style="z-index: 1011; position: absolute; padding: 0px; margin: 0px; width: 1365px; top: 50px; left: 50px; text-align: left; color: rgb(0, 0, 0); border: 0px none; background-color: rgb(255, 255, 255);">
<div class="White" style="margin: 0px 20px 20px; display: block;">
<div class="PopUpClose" align="right">
<div>
<div align="center">
<table style="width: 100%;">
<tbody>
<tr>
<td valign="top" align="left" style="width: 410px;">
<div class="orgSelection">
<span id="dataAccessOrgSelection" class="">Select org unit(s)</span>
Here is the HTML for this element in section B when it is NOT displayed (hidden when section A is displayed)
<div class="White" style="margin: 0px 20px 20px; display: none;">
<div class="PopUpClose" align="right">
<div>
<div align="center">
<table style="width: 100%;">
<tbody>
<tr>
<td valign="top" align="left" style="width: 410px;">
<div class="orgSelection">
<span id="dataAccessOrgSelection" class="">Select org unit(s)</span>
To select the element in section A, I could use the ID and it will work
css=#selection
To select the element in section B, I could also use it's id and it will work
css=#dataAccessOrgSelection
I wanted to have 1 selector for this element, so I tried this. However, it selects both the displayed and hidden elements. So if I'm on section A, it will select the element for both A and B, even though B is hidden (and vice-versa)
div.orgSelection span[id]
Is there a way to have 1 selector for this element, that will only select the visible element? I could check for "display:none" in the style attribute, but I'm not sure how to do this when it is located in td for section A, and div for section B.
Okay, if I understand your question right, you need CSS selector valid for both A and B in visible state.
td#treeCol[style*=block] span#selection, div.PopUp>div[style*=block] span#dataAccessOrgSelection
A tiny explanation. Comma - is for logical OR in CSS selectors. Visible divs of yours have a part of their style attribute - block ([style*=block]). So for both selectors we find span with needed id being contained inside a visible div. If the sectors are not right enough, play with attributes a little more.
To be completely sure that your approach works, you should call the element location with this selector every time before checking its visibility to avoid StaleElementReferenceException, because, clearly, those elements are not the same
But, if I was you, I would check a specific logic and not the 'what if' case. You should know exactly when and what element should be visible.
As Alexander Petrovich mentioned, I would recommand to use to different element-selectors, because in my opinion, they are indeed different elements. In this case, you can find easy selectors with ids.
But if there's a valid reason for a one-selector-but-two-elements-constuct, you need to make clear, which parts of your dom may vary and which are stable. I'm not so firm with css, but I can give you some xpath expressions, if this helps:
//span[(#id='dataAccessOrgSelection') or (#id='selection')]
//span[#class='']
//span[contains(text(),'Select') and contains(text(),'org unit')]
//div[#class='orgSelection']/span
I guess you will be able to transform this xpath-selectors into css-selectors...maybe this pdf will help:
http://code.google.com/p/timger-book/source/browse/trunk/cheatsheet/Locators_table_1_0_2.pdf

Creating complex div structure using CSS

I'm attempting to create a complex div structure using CSS.
I want it to be made up of four columns. On the left is just a list of images. On the right is the complex div structure that I can't figure out a way to create. There should be two large vertical boxes containing various details. In-between these vertical boxes are any number of horizontal boxes.
My problem is that I cannot work out how to create this div structure in a way that 'scales', i.e. there could be any number of horizontal boxes between the two vertical boxes.
This is the div structure I was attempting to use:
<div class="result">
<div class="detail_1">
<p>Detail 1</p>
</div>
<div class="details">
<p>Details</p>
</div>
<div class="details">
<p>Details</p>
</div>
<div class="detail_2">
<p>Detail 2</p>
</div>
</div>
Any help would be greatly appreciated!
EDIT: I have fixed this problem by just using tables. Thanks for the replies.
Update 2
Your question is: How to make the price & flight_number div the same height as the parent div (container)..
1) Use the technique described here: http://matthewjamestaylor.com/blog/equal-height-columns-cross-browser-css-no-hacks
2) update your CSS so that the flight number and the price are vertical aligned in the middle of their div.
I think that mine HTML structure is better then yours because it's more clear and easier to work with.
So based on my HTML structure: The parent container (flight_info) is stretchend as long as the content inside (the table with the rows will be the longest). the div's flight_number and price are also the total height of the parent container thanks of the technique described in step 1 above. The extra CSS (step 2) will align the price and flight number nicely in the middle.
OLD
<ul id="flights">
<li>
<ul class="images">
<li><img src="img1" alt="your image" /></li>
<li><img src="img2" alt="your image 2" /></li>
</ul>
<div class="flight_info" id="flight_EK49">
<div class="flight_number">
EK49
</div>
<table>
<thead>
<th>date</th>
<th>from</th>
<th>to</th>
</thead>
<tbody>
<tr>
<td>1/1/2013</td>
<td>departure airfield</td>
<td>destination airfield</td>
</tr>
...
</tbody>
</table>
<div class="price">
€999,99
</div>
</div>
</li>
// duplicate the above for a new flight..
</ul>
And for the CSS style (you must do the rest on your own because this is just an example. I didn't test any of the code):
<style>
#flights .images {
float: left;
width: 250px;
}
.flight_info {
float: left;
width: 700px;
}
.flight_info .flight_number,
.flight_info .price {
float: left;
width: 150px;
}
.flight_info .price {
float: right;
}
.flight_info table {
float: left;
width: 400px;
}
</style>
I think you will get the idea.
EDIT 1
Changed all the position absolutes to floats because it easier with the li's automatic heights.
I also added the leg images of the flight as well, but as I mentioned, you have to do the rest yourself ;)

css selector question

I have a table that looks something like this.
EDIT - I re-extracted code. I think the question makes more sense now. (Answers may not)
<div class="view view-latest-news-view view-id-latest_news_view view-display-id-latest_news_block_1 view-dom-id-1">
<div class="views-admin-links views-hide">
</div>
<div class="view-content">
<table class="views-view-grid">
<tr class="row-1 row-first">
<td class="col-1">
</td>
</tr>
<table>
</div>
</div>
How can I address only the "views-view-grid" tables that are contained by the "view-latest-news-view" class? Something like this...
.view-latest-news-view table.views-view-grid {
border-collapse:separate;
border: 1px solid red;
}
** END EDIT **
Thanks!
** ANSWER: **
this works... but maybe I could be more specific?
.view-latest-news-view .views-view-grid {
border-collapse:separate;
border: 1px solid red;
}
This does not work because <table class="views-generic-grid"> is not contained with in any element with the class views-admin-links. (You open the div and then immediately close it, so it has no children.)
So when you say this:
How can I address only the "views-generic-grid" tables that are contained by the "views-admin-links" class?
The answer is you can't, because there are no "views-generic-grid" tables contained in elements with the "views-admin-links" class.
Either extend the div to surround the table, or pick a different selector than .views-admin-links.
The way your markup is right now, you can't, you have to extend .views-admin-links to surround the entire .views-generic-grid table, and then you can write a selector like this:
.views-admin-links .views-generic-grid

Resources