0

I am trying to dynamically set the left of a div depending upon the quantity of elements in an array. To do this, I am using the calc() method in my [ngStyle], where data.questions is an array of objects on which I draw from.

To prove that the calculation works, I added it into a <p> for debug purposes.

I have the following in my html:

<div id="progress">
    <div *ngFor="let question of data.questions; let i = index;"
         [ngStyle]="{'left': 'calc('+(i / data.questions.length * 100) + (1 / (data.questions.length * 2) * 100)+'%)'}">
        <p>{{(i / data.questions.length * 100) + (1 / (data.questions.length * 2) * 100)}}%</p>
    </div>
</div>

Below is the rendered content. You can see that the [ngStyle] is only working for the first of the 3 generated divs. Why is this the case?

<div _ngcontent-ydx-7="" id="progress" ng-reflect-ng-style="[object Object]" style="border-color: rgb(127, 167, 187);">
    <div _ngcontent-ydx-7="" ng-reflect-ng-style="[object Object]" style="left: calc(16.6667%);">
        <p _ngcontent-ydx-7="">16.666666666666664%</p> 
    </div>
    <div _ngcontent-ydx-7="" ng-reflect-ng-style="[object Object]">
        <p _ngcontent-ydx-7="">49.99999999999999%</p>
    </div>
    <div _ngcontent-ydx-7="" ng-reflect-ng-style="[object Object]">
        <p _ngcontent-ydx-7="">83.33333333333331%</p>
    </div>
</div>

note: I spent a considerable time trying to make a plunkr for this, however it kept giving me errors with using data.questions in my ngFor even though this definitely works as proved above (my plunkr skills are a work in progress....).

Below is a simplified version of data.questions for people to play with...

private questionOptions: string[] = [
  `Strongly Agree`,
  `Agree`,
  `Slightly Agree`,
  `Slightly Disagree`,
  `Disagree`,
  `Strongly Disagree`
];

private data = {
  questions: [{
      text: `Great service makes a difference to the customer.`,
      options: [{
          text: this.questionOptions[0],
          score: 3
        },
        {
          text: this.questionOptions[1],
          score: 2
        },
        {
          text: this.questionOptions[2],
          score: 1
        },
        {
          text: this.questionOptions[3],
          score: -1
        },
        {
          text: this.questionOptions[4],
          score: -2
        },
        {
          text: this.questionOptions[5],
          score: -3
        }
      ]
    },
    {
      text: `Great service can be provided every time we interact with our customers. `,
      options: [{
          text: this.questionOptions[0],
          score: 3
        },
        {
          text: this.questionOptions[1],
          score: 2
        },
        {
          text: this.questionOptions[2],
          score: 1
        },
        {
          text: this.questionOptions[3],
          score: -1
        },
        {
          text: this.questionOptions[4],
          score: -2
        },
        {
          text: this.questionOptions[5],
          score: -3
        }
      ]
    },
    {
      text: `Customer facing staff have more impact on providing great service than I do.`,
      options: [{
          text: this.questionOptions[0],
          score: -3
        },
        {
          text: this.questionOptions[1],
          score: -2
        },
        {
          text: this.questionOptions[2],
          score: -1
        },
        {
          text: this.questionOptions[3],
          score: 1
        },
        {
          text: this.questionOptions[4],
          score: 2
        },
        {
          text: this.questionOptions[5],
          score: 3
        }
      ]
    }
  ]
};
Zze
  • 18,229
  • 13
  • 85
  • 118
  • Why is your css property value wrapped with `'`s? – eko Feb 28 '17 at 05:07
  • [style.left]="calc("+(i / data.questions.length * 100) + (1 / (data.questions.length * 2) * 100)"+"%)" – micronyks Feb 28 '17 at 05:08
  • Don't see the need to use `calc()` here. – Robby Cornelissen Feb 28 '17 at 05:14
  • @RobbyCornelissen sorry - I stripped out all the other parts of the equation in order to simplify the question. They are rather lengthy and was going to leave them until I noticed it didn't work with just the percentage. – Zze Feb 28 '17 at 05:18
  • @echonax don't I have to do that so it doesn't try and transmute `calc()` into a typescript function and instead passes it as a string value? – Zze Feb 28 '17 at 05:22
  • Thanks @micronyks I will check this and get back to you. – Zze Feb 28 '17 at 05:22

2 Answers2

3

Before

calc(016.666666666666664%)

calc(33.3333333333333316.666666666666664%)

calc(66.6666666666666616.666666666666664%)

They are not valid styles (except the first iteration). You need to wrap your calculations in brackets like

'calc(' + // string

((i / data.questions.length * 100) + (1 / (data.questions.length * 2) * 100)) + // number

'%)' // string

Summary

[ngStyle]="{'left': 'calc('+((i / data.questions.length * 100) + (1 / (data.questions.length * 2) * 100))+'%)'}"

Plunker Example

yurzui
  • 205,937
  • 32
  • 433
  • 399
  • haha This totally makes sense! whoops. I will check this at work tomorrow - thanks for the help. – Zze Feb 28 '17 at 11:28
0
<div id="progress" *ngIf="data">
    <div *ngFor="let question of data.questions; let i = index;"
         [ngStyle]="{'left': 'calc(i)'}">
        <p>{{(i / data.questions.length * 100) + (1 / (data.questions.length * 2) * 100)}}%</p>
    </div>
</div>



calcLeftPostion(index: number){
     let dataLength = this.data !== null ? this.data.questions.length : 0;
     return ((i / dataLength  * 100) + (1 / (dataLength  * 2) * 100))+ '%';
}
Yoav Schniederman
  • 5,253
  • 3
  • 28
  • 32