0

I am having a scenario where the selected items are overflowing the div. But I have managed to wrap it by css properties.

Now I am planning to put a css badge if the content width is crossing the parent div to transform from image 1 to image 2:

enter image description here

enter image description here .

<div class="list-view">
    <div class="item-box">
        <h4>select Cities</h4>
        <ul>
            <li *ngFor="let item of cityList" (click)="selectedCity(item)">{{item}}</li>
        </ul>
    </div>
</div>

I have a sample code from this link https://stackblitz.com/edit/angular-uatw5p. I tried to achieve this but couldn't find a way. Can anyone let me know how to achieve this??

Onera
  • 687
  • 3
  • 14
  • 34
  • 1
    There's the CSS `overflow-wrap` rule ( or word-wrap ) https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-wrap that you can use to automatically wrap the text inside the div. And you can use the :after pseudo element to add the icon, so that you can position the icon relative to the div,. no matter how much overflowing or wrapping text there is inside it. – Shilly Jun 12 '19 at 12:26

6 Answers6

1

Slice the list of array for the number of items you want to display. I used three items to display. And minus three from the total length of array. Use the CSS to format it the way you want.

<div class="container-fluid">
  Cities
    <a *ngFor="let item of selectedItems.slice(0, 3)" href="javascript:void(0)">{{item}}</a>
   <div *ngIf="selectedItems.length > 3">+{{selectedItems.length - 3}}</div>
    <button (click)="selectedItems=[]">Reset</button>
</div>

The above will give you the following result:

enter image description here

Edit: Use the following with the CSS provided in the another answer:

<a href="javascript:void(0)" class="selection">
   <p>Cities {{selectedItems.length? ' : ' + selectedItems.slice(0, 3): '' }}</p>
  <span *ngIf="selectedItems.length > 3">+{{selectedItems.length - 3}}</span>
</a>
Maihan Nijat
  • 9,054
  • 11
  • 62
  • 110
  • I dont have problem in slicing the list. I have problem in restricting the content and placing that +4 after selection – Onera Jun 12 '19 at 12:27
  • I guess I was not clear. I have updated my question please check once – Onera Jun 12 '19 at 12:36
  • Is there someway that I could check for max-width instead of *ngIf="selectedItems.length > 3" – Onera Jun 12 '19 at 12:48
  • Not sure about `max-width` but this might help: https://stackoverflow.com/questions/48708119/how-to-get-width-of-dom-element-in-angular-4-after-page-is-loaded?rq=1 – Maihan Nijat Jun 12 '19 at 12:55
  • You can easily check the max-width by binding it, use inline CSS, and bind. – Maihan Nijat Jun 12 '19 at 12:56
1

I would ellipsis the text to always allow space for the badge:

p {
    display:block;
    text-overflow: ellipsis; /* will make [...] at the end of only ONE LINE!*/
    -webkit-line-clamp: 2; // experimental only! would allow ellipsis on 2nd line
    width: 370px; /* change to your preferences */
    white-space: nowrap; /* paragraph to one line */
    overflow:hidden; /* older browsers */
}
E_net4
  • 27,810
  • 13
  • 101
  • 139
Ben Racicot
  • 5,332
  • 12
  • 66
  • 130
  • 1
    thanks pal. Your code is helped me to restrict with ellipses but do you have any idea how can I show a badge saying +2 more selected instead of hiding – Onera Jun 12 '19 at 12:33
  • Here it is but you'll have to add your requirements to it. Try this: https://stackblitz.com/edit/so-56562044 – Ben Racicot Jun 12 '19 at 12:52
1

It is the problem with text "Chennai,Mumbai,Pune,Bangalore" without spaces. If there is space, there would be on overflow of tex outside div

If you still require badge based on the text overflow, you need to add or remove css class based on parentDiv.offsetWidth and textDiv.offsetWidth. Css will dictate to show or hide the badge including ellipsis of text.

enter image description here

schoolcoder
  • 1,546
  • 3
  • 15
  • 31
1

Try the following html for the anchor tag, manipulate the content by checking array length:

<a href="javascript:void(0)"> Cities {{selectedItems.length? (selectedItems.length < 3 ? ' : ' + selectedItems : ' : ' + selectedItems.slice(0,3) + '+' + (selectedItems.length-3) ): '' }}</a>

Output

Output

shrys
  • 5,860
  • 2
  • 21
  • 36
1

I would use a combination of overflow, overflow-wrap and white-space to make the text break correctly.

Then I would use a pseudo element to render the item count after the container. By putting it absolute, we can align ther element relative to the container, no matter how many extra nodes we add to the container.

Since we use a pseudo-element, we can easily use the content css rule to bind the data-items attribute of the HTML container as the content of our little counter.

The big advantage is that by positioning the counter absolutely, we can keep using relative units to position everything else and we can put the counter anywhere we want, including putting overflow back on hidden and have the counter overlap the border.

const cities = [
  "amsterdam",
  "belize",
  "calcutta",
  "dortmund",
  "egmond aan zee",
  "frankfurt",
  "gotenburg"
];

const render_list = list => content => {
  const items = content.map( text => `<li>${ text }</li>` ).join( '' );
  list.innerHTML = items;
  return list;
};

const add_city = list => event => {
  const item = event.target;
  if ( event.target.nodeName === 'LI' ) {
    list.appendChild( item.cloneNode(true));
    list.setAttribute( 'data-items', list.childElementCount );
  }
};

const options = document.querySelector( '#options' );
const selections = document.querySelector( '#selections' );

options.addEventListener( 'click', add_city( selections ));

render_list( options )( cities );
#selections {
  background-color: steelblue;
  border: 1px solid grey;
  list-style: none;
  margin: 4px;
  max-width: 50%;
  min-height: 1.1em;
  overflow-wrap: break-word;
  position: relative;
  width: 50%;
}
#selections:after {
  background-color: white;
  border: 1px solid grey;
  content: '+' attr(data-items);
  position: absolute;
  left: 100%;
  top: -1px;
}
#selections > li {
  display: inline;
  margin-left: 2px;
}
#options {
  border: 1px solid grey;
  margin-top: 20px;
}
<ul data-items="0" id="selections"></ul>
<ul id="options"></ul>
Shilly
  • 8,511
  • 1
  • 18
  • 24
0

If it helps, one simple css fix as overflow-wrap: break-word; by using word-break property

a{
  text-decoration: none;
  color: black;
  background: skyblue;
  display: block;
  width: 20em;
  margin: 20px auto;
  padding: 1.2em;
  font-size: 18px;
  max-width: 16em;
  overflow-wrap: break-word;
}

op

Sai Manoj
  • 3,809
  • 1
  • 14
  • 35