Search code examples
cssangulartypescriptrating

Typescript rating component not displayed correctly


I have written some code to rate . So I created the HTML and CSS files. I have given rating as 4 and 5. But it displaying both as 5 stars only. When I debug it is taking input as "4" but display as"5" and the stars are displayed over two lines.

An image showing the problem:
![Stars in two lines][2]

I am attaching my code here. Please help me.

rating component.html

//**rating.component.ts**


    import {
      Component,
      OnChanges,
      Input
    } from '@angular/core';

    @Component({
      selector: 'app-rating',
      templateUrl: './rating.component.html',
      styleUrls: ['./rating.component.css']
    })
    export class RatingComponent implements OnChanges {
      @Input() rating: number;

      starWidth: number;
      constructor() {
        console.log("star has created");
      }

      ngOnChanges() {
        console.log("star dynamically added");
        this.starWidth = this.rating * (86 / 5);
      }

    }
//mobile.component.ts
import {
  Component,
  OnInit
} from '@angular/core';
import {
  mobile
} from './mobile'

@Component({
  selector: 'app-mobiles',
  templateUrl: './mobiles.component.html',
  styleUrls: ['./mobiles.component.css']
})
export class MobilesComponent implements OnInit {
  title: string = 'MOBILE CART';
  image: string = 'assets/images/';
  click: boolean = false;
  showImages: boolean = true;
  refineMobile: string = " ";
  shop = 'assets/images/Cart.jpg';
  mobiles: mobile[] = [{
      //imageUrl: 'assets/download.jpg',
      imageUrl: 'download.jpg',
      mobile_name: 'Lenovo',
      mobile_price: 10000,
      mobile_code: 'K3',
      release_date: 'mar 19,2016',
      rating: 4
    },
    {
      //imageUrl: 'assets/download (1).jpg',
      imageUrl: 'download (1).jpg',
      mobile_name: 'samsung',
      mobile_price: 7000,
      mobile_code: 'ON-5',
      release_date: 'nov 18,2017',
      rating: 5
    }
  ];
  displayImages(): void {
    (this.showImages == true) ? this.showImages = false: this.showImages = true;
  }
  cart: number = 0;
  //adding items in cart
  inCart() {
    console.log("item are added in the cart");
    return this.cart++;
  }
  //clearing the cart
  clear() {
    return this.cart = 0;
  }

  ngOnInit(): void {
    console.log('oninit of angular is initialised');
  }

  //filter by name
  filterMobiles: mobile[];
  _listFilter: string;
  constructor() {
    this.filterMobiles = this.mobiles;
    this.listFilter = '';
  }
  get listFilter() {
    return this._listFilter;
  }
  set listFilter(value) {
    this._listFilter = value;
    this.filterMobiles = this.listFilter ? this.performFilter(this.listFilter) : this.mobiles;
  }
  performFilter(filterBy: string): mobile[] {
    filterBy = filterBy.toLocaleLowerCase();
    return this.mobiles.filter((mobile: mobile) =>
      mobile.mobile_name.toLocaleLowerCase().indexOf(filterBy) !== -1);
  }

}
/*rating.component.css*/
.crop {
  overflow: hidden;
}

div {
  cursor: pointer;
}
#star{
  color:gold;
}
/*mobile.componet.css/
h1,p{
  font-style: initial;
  color:green;
  text-align: center;
  border: dashed;
}

td {
  font-family: Tahoma;
}
.col-md-2{
  background-color: blue;
  color: white;
}
h4 {
  color: red;
  text-align: right;
  border-radius: 3px;
  background-color: rgba(0, 0, 0, .1);
  height: 20px;
  padding: 3px 6px;
  font-weight: 500;
  display: inline-block;
  line-height: 12px;
  margin-left: 100px;
}
#clear{
  float:right;
}
<!--rating.component.html-->
<div class="crop"
     [style.width.px]="starWidth"
     [title]="rating">
  <div style="width: 86px" id="star">
    <span class="glyphicon glyphicon-star-empty"></span>
    <span class="glyphicon glyphicon-star-empty"></span>
    <span class="glyphicon glyphicon-star-empty"></span>
    <span class="glyphicon glyphicon-star-empty"></span>
    <span class="glyphicon glyphicon-star-empty"></span>
  </div>
</div>

<!--mobiles.component.html-->
<h1>MOBILE CART</h1>
<div class="container">
  <div class='col-md-2'>
    Refined by:{{listFilter}}
  </div>
  <div class='col-md-1'>
    <input type="text" [(ngModel)]="listFilter">
  </div>
</div>

<!--<h4>{{cart}}</h4>-->
<img src="{{shop}}" width="50" align="right" />

<table class="table ">

  <tr>
    <th>
      <button class='btn btn-primary' (click)="displayImages()">
        Display Images
      </button>
    </th>
    <!--<th>Image</th>-->
    <th>NAME</th>
    <th>PRICE</th>
    <th>CODE</th>
    <th>RELEASE DATE</th>
    <th>RATING</th>
    <th>CART </th>
  </tr>
  <tr *ngFor='let mobile of filterMobiles'>
    <td>
      <div [hidden]="showImages">
        <!--<img src="{{mobile.imageUrl}}" width="100" />-->
        <img [src]="image+mobile.imageUrl" width="100" />
      </div>
    </td>

    <td>
      {{mobile.mobile_name|uppercase}}
    </td>
    <td>
      {{mobile.mobile_price|currency:'INR':'1.2-2' }}
    </td>
    <td>
      {{mobile.mobile_code|separator:'_'}}
    </td>
    <td>
      {{mobile.release_date|date:'longDate'}}
    </td>
    <td >
      <!--{{mobile.rating}}-->
      <app-rating [rating]='mobile.rating'></app-rating>
    </td>
    <td>
      <button class="btn btn-primary" (click)="inCart()">
        Add to cart
      </button>
      <button class="btn btn-primary">
        Buy Now
      </button>
    </td>
  </tr>
</table>
<p>{{cart}} items are added into the cart</p>
<button class="btn btn-primary" (click)="clear()" id="clear">
  CLEAR
</button>

Thanks in advance for any help.


Solution

  • As the problem here seems to be how your app is being rendered, I've boiled your code sample down to a MCVE. So this is where we start:

    .crop {
      overflow: hidden;
    }
    #star {
      color: gold;
      width: 100px;
    }
    td {
      font-family: Tahoma;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://netdna.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
    <link rel="stylesheet" href="https://netdna.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
    <table class="table">
      <tr>
        <td>
          <div class="crop" title="rating">
            <div style="width: 86px" id="star">
              <span class="glyphicon glyphicon-star-empty"></span>
              <span class="glyphicon glyphicon-star-empty"></span>
              <span class="glyphicon glyphicon-star-empty"></span>
              <span class="glyphicon glyphicon-star-empty"></span>
              <span class="glyphicon glyphicon-star-empty"></span>
            </div>
          </div>
        </td>
      </tr>
    </table>

    First of all, removing Tahoma from the <td> containing your stars seems to fix your wrapping issue. I assume the glyph width of Tahoma differ from the glyph width of Bootstrap Glyphicons Halflings which is used to display your stars.

    This can be done by applying a class name to the <td> (e.g. class="star-ratings") and excluding this in the CSS using the :not() negation pseudo class.

    td:not(.star-ratings) {
      font-family: Tahoma;
    }
    

    While this seems to fix the issue (at least in Chrome), it isn't a very viable solution on its own. In addition to the above, apply white-space:nowrap to #star. This prevents the stars from wrapping to a second line.

    #star {
        white-space: nowrap;
    }
    

    I would also remove the hard coded, inline width of 86px applied to #star. Inline styles have higher specificity than other rulesets, so this will overrule the width of 100px applied in your CSS. This leaves us with the following:

    .crop {
      overflow: hidden;
    }
    #star {
      color: gold;
      width: 100px;
      white-space: nowrap;
    }
    td:not(.star-ratings) {
      font-family: Tahoma;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://netdna.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
    <link rel="stylesheet" href="https://netdna.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
    <table class="table">
      <tr>
        <td class="star-ratings">
          <div class="crop" title="rating">
            <div id="star">
              <span class="glyphicon glyphicon-star-empty"></span>
              <span class="glyphicon glyphicon-star-empty"></span>
              <span class="glyphicon glyphicon-star-empty"></span>
              <span class="glyphicon glyphicon-star-empty"></span>
              <span class="glyphicon glyphicon-star-empty"></span>
            </div>
          </div>
        </td>
      </tr>
    </table>