Ordering N elements into columns, via ng-repeat - javascript

So I have a bit of a head-scratcher on my hands.
I'm using ng-repeat to output a list of items that are positioned inside a widget.
The widgets are resizable, with three available sizes. The first two are only wide enough to have one column of elements, so displaying them in the correct order is trivial. However, when the widget is expanded to twice width, more elements are displayed at 50% of the width. The elements are arranged by default using display:inline-block; float: left which means that I end up with the ordering going from left -> right, whereas I need them to be ordered vertically.
Initially I was performing two ng-repeats with a column wrapper around each, using splice to split the results, however this causes problems with ordering, because each set of elements is only ordered relative to its container column.
So here's some stripped down code from one of the widgets:
<div class="item review" ng-repeat="review in reviews | orderBy:'date':true | limitTo:14">
<div class="header">
...
</div>
<div class="body">
<div class="comment">
<p>{{review.comments}}</p>
</div>
</div>
I would quite happily use ng-if alongside an $index comparison, something like ng-if="($index+1)==7" on the element I'd like to insert before a group, but since the ng-repeat is on the items themselves, I can't wrap them with that method.
I've tried various ideas with no real success so far. There are things I can do outside of Angular but it's messy and I would like to keep in within Angular, I'm sure what I'm after is possible. Can somebody save me?
EDIT: Illustration of what I mean

working plunk:
http://plnkr.co/edit/lP3vc57k98gPUEbShHWT
You can use css3 column-count or its shorthand columns:
ul {
-webkit-column-count: 2; /* Chrome, Safari, Opera */
-moz-column-count: 2; /* Firefox */
column-count: 2;
}

Related

Calculate correct height of div based on different children in slider?

I have a slider in a <div>. The slider takes an array of slides and each element has a text where there is no word-limit on the text. When I slide left or right, and the different texts are of different lengths, the height of the <div> varies, making it look ugly. I tried using a min-height or a fixed height, but those don't solve the problem, since there will either be too much empty space underneath the text, or, a text once in a while will be longer than the min-height and the size of the <div> will vary again.
What could I do now? Is there a way for me to find out what maximum height the div should have (based on what's the longest text in my array of slides) and then give my div this height? This way there would still be some empty space with the shorter texts, but at least it wouldn't be arbitrary.
Does this sound like an ok solution? I am wondering how I can measure this beforehand though? So I'm thankful for any clues!
If I understand your situation, you have a <div> element that wraps multiple "slide elements" where;
each slide element varies in height based on their text content and,
you'd like the wraping div to natually expand to fit around all slides regardless of the arbitrary height of their content
One solution to this would be to use flex-box which would allow your slides to be arranged horizontally within the wrapper div, while also ensuring that the wrapper naturally expands to fit around it's children (of arbitrary height).
To illustrate this approach, consider the following example where flex box is used to ensure the pink div correctly wraps green slides (of differing height):
#wrapper {
display:flex;
flex-direction:row;
overflow-x:scroll;
background:pink;
}
#wrapper > div {
min-width:30rem;
margin:1rem;
background:green;
}
<div id="wrapper">
<div><p>Short</p></div>
<div><p>Tallest<br>Tallest<br>Tallest<br>Tallest<br>Tallest</p></div>
<div><p>Tall<br>Tall<br>Tall</p></div>
</div>
You could try to use flex display to achieve this. Not sure if it will work with your slider tho, since tho have not posted your code.
You can find an example here

jquery: dynamic ID parent selector, childrens fit to parent

this is my first question!
I'm working on a healthcare app and the code is very dynamic, sometimes I have 1 column and sometimes I've 4 so I'm using an incremental Id selector (i)
Inside this container I've divs that can be 1 to 4...
if there are only one the height might be 100%, if it is three 33%.. and so on..
What I need is to fit the content div to his parent container (i).
The problem is that I need and specific function for each column
It cant be solved by CSS because my clients are in a very old version of IE
<div id="column-1"><!--"1" is dynamic -->
<div id="row-1"></div>
<div id="row-2"></div>
<div id="row-3"></div>
<!-- number of rows is dynamic -->
</div>
PS: tomorrow I'll edit with the real code, and sorry for my english ;)
Fix the DOM height and then use 'overflow-y' CSS property to get scroller, if your
list grows.
column-1 {
height: 110px;
overflow-y: overflow;
}

Adding a wrapper around some elements in an ng-repeat

It is possible to use an ng-repeat to achieve the following compiled DOM:
<div class="container">
<!-- ngRepeat item in items -->
<div ng-repeat="item in items">Item 1</div>
<!-- end ngRepeat: item in items -->
<!-- ngRepeat item in items -->
<div ng-repeat="item in items">Item 2</div>
<!-- end ngRepeat: item in items -->
<!-- ngRepeat item in items -->
<div ng-repeat="item in items">Item 3</div>
<!-- end ngRepeat: item in items -->
<div class="wrapper">
<!-- ngRepeat item in items -->
<div ng-repeat="item in items">Item 4</div>
<!-- end ngRepeat: item in items -->
<div ng-repeat="item in items">Item 5</div>
<!-- end ngRepeat: item in items -->
</div>
</div>
i.e. to have the last n items wrapped in an another element.
It might seem like a strange request and I understand it would be trivial to achieve this using two ng-repeat directives. However, it needs to be a single ng-repeat so that I can move items in and out of the wrapper without them being added and removed from the DOM (in a manner described here).
What I'm trying to achieve is a news-ticker style scrolling effect by giving the .wrapper element overflow:hidden and using javascript animate the top position of the child elements. To be honest I'd rather not have to have a wrapper element at all but I'm not sure there is any other way to achieve the scrolling effect I require. Perhaps manipulating the clip property to achieve the effect could work but I'm not entirely sure.
So it is possible to apply a wrapper element to some items in an ng-repeat?
Unfortunately, when you change the parent of an element in the visual tree, it must be removed and re-added. Among other problems, consider how styling rules might be applied differently depending on who is whose parent. It's also a pretty expensive thing to do in an animation.
Disappointing? Perhaps.
But reading through your use case, I think you'll find Angular is very good at handling this sort of animation with just a tiny bit of code. I've included a fiddle for you to play with:
http://jsfiddle.net/wjxgcb0k/
It's very easy to create and bind your own layout to the elements on the page. We'll first use ng-repeat to spit out one row per item:
<div class="container" ng-app ng-controller="Foo">
<div class="item"
ng-repeat="item in items"
ng-style="{'top': item.top + 'px'}">{{item.name}}
</div>
</div>
Because we want to handle our own layout, each item in the container will be position: absolute. See how we bind the top to item.top + 'px'? All we need to do is adjust those top values in an animation loop. I'm going to use requestAnimationFrame because it's my go to tool for manual animation, but you can use css transitions or animations if you are more comfortable.
I'll initialize the top values in the controller. That's what it's for, holding state:
$scope.items.forEach(function(item, idx) {
item.h = height;
item.top = idx * (height + margin);
console.log(item);
});
And then I'll set up an animation loop:
var tick = function() {
$scope.$apply(function() {
$scope.items.forEach(function(item, idx) {
item.top -= velocity;
if (item.top < -(height + margin)) {
item.top += $scope.items.length * (height + margin);
}
});
});
requestAnimationFrame(tick);
};
And then kick off the whole thing:
requestAnimationFrame(tick);
Some neat improvements you can make with this:
Consider only animating as many items as will fit on the page, rather than all of the items in the collection. Performance will thank you.
Instead of relying on the $apply to propagate changes to the Dom, directly manipulate the style yourself. This can improve animation performance.
When the if condition fires and we reset the item to the bottom of the ticker, we might check to see if there is different content to be put into the ticker item. This way you might have a live updating ticker that changes over time.
Try your hand at making this all work horizontally. Or perhaps adjust the opacity as top approaches zero or the bottom half of the list.
I hope this helps, and I hope that the small amount of code needed to do this will encourage you to leave behind the notion of relying on the HTML to do your layout for you.
Technically, the answer is no because the wrapper exists outside the scope of the ngRepeat. So it's not possible to set conditions on the wrapper based upon a property of each item.
You can on the other hand still reproduce the same markup. It just requires filtering and some creative thinking.
<div class="container">
<!-- items with wrapper = false are outside wrapper -->
<div ng-repeat="item in items | {'wrapper':false}">{{item}}</div>
<div class="wrapper">
<!-- items with wrapper = true are inside wrapper -->
<div ng-repeat="item in items | {'wrapper':true}">{{item}}</div>
</div>
</div>
I actually don't know whether it is possible to wrap N items inside block using ng-repeat. But what can be done is to apply .wrapper class to every element with index higher than 'some value'. That can be done using ng-class and $index.
edit:
hope I understood how new-ticker works. If not, sorry for the wrong answer.
plnkr
<div ng-repeat="op in options" ng-class="{wrapper: $index > limit}">{{op.title}}</div>
in the sample you can change model value of 'limit' variable to change number of visible items.
or better yet. If the items inside of the wrapper should "be appearing", maybe easiest approach would be
ng-hide="$index > end || $index < start"
This would hide items at the start and at the end. Manipulating values of 'start' and 'end' would create the effect.
Can you achieve this using CSS and nth:child to access the last two elements? You can make the visibility: hidden, for these two nodes in the ng-repeat. You can even do CSS animation with delays.

navigation 100% spread within a div with even padding

Hello!
I want to build a website navigation that is 100% spread within a tag and has even padding. The navigation items have no fixed number, they can be added dynamically. Or even not added, the site will be multilingual, so in different languages the size of the 'li' tags will differ.
I would like to know whether I can use js or jquery or any other method to calculate the sizes of all 'li' elements and give them a width (or padding) that will evenly spread my 'li' elements within the 'div'.
I looked for websites the like and found that cnn.com uses something like this but could not find what exactly.
Make all of your <li> tags inline-block and do text-align: justify on the parent, set to display: block and width: 100%. It should space them all out evenly and you can add whatever padding/margins you want.

fill container with floating divs according to window size & adjust width of divs to set max

im working on a page layout for a magazine. it now has 5 different categories - each of the categories is displayed on the main site inside a separate div floating left. so it looks like this
--------------page width-------------
-category1--category2--category3-
-category4--category5-
now i would like to have the three categories in first and second line stretch to take all the space until they reach a set amount of width and then fall back to a lower width to give more categories room in the first row on a page resize:
(4 divs with min width does NOT fit inside the page width)
-----------------page width-----------
-category1 --category2 --category3 -
-category4 --category5 -
then on resize (as soon as 4 elements with the min-width fit in):
------------------------page width----------
-category1--category2--category3--category4-
-category5-
is this possible with css? (i don't think so) or with some javascript calculation. i tried a lot, but my java skills are just really bad ...
thanks so much! nice greets from vienna
I don't think you need any javascript to achieve this. I think what you're after is a media query within your css.
CSS has the ability to target css rules at specific canvas widths, device widths or orientations. So you could have markup like this
<div class="container">
<div class="category-wrapper"></div>
<div class="category-wrapper"></div>
<div class="category-wrapper"></div>
<div class="category-wrapper"></div>
<div class="category-wrapper"></div>
</div>
And then change the widths of the category wrappers with CSS like this
.category-wrapper{
float:left;
width:100px;
}
#media (min-width:500px) and (max-width:950px){
.category-wrapper{
width:200px;
}
}
#media (min-width:950px) and (max-width:1024px){
.category-wrapper{
width:400px;
}
}
and so on.
See the spec for media queries here http://www.w3.org/TR/css3-mediaqueries/ a great primer on the concept of this way of working here http://www.alistapart.com/articles/responsive-web-design/
and since not all browsers support them, use Scott Jehl's amazing polyfill https://github.com/scottjehl/Respond to help out the laggers.
Hope this helps.

Categories

Resources