在Angular中对(点击)进行样式绑定

问题描述 投票:0回答:1

我想做一个交互式座位图,如果你点击座位,它就会改变颜色。我找到了一些解决方案,但他们没有工作。

我有一个SVG元素。我想让黑色的矩形在被点击时变成红色。

<g>
  <rect [style.color]="toggleColor()" (click)="toggleStyle = !toggleStyle;" id="2a" x="90.714" y="65.012" width="27.97" height="30.994"/>
</g>

组件中的代码如下。

public toggleStyle: boolean = false;

toggleColor() {
  console.log("does it work?")
  if (this.toggleStyle) {
    return "red";
  } else {
    return "";
  }
} 

}

正如你在stackblitz上看到的那样--这并没有给矩形添加颜色。此外,由于它是元素的一部分,该函数运行了两次。

STACKBLITZ

谢谢你对如何解决这个问题的任何建议!我想做一个交互式座位地图,如果你点击座位,它就会改变颜色。

angular binding onclick styling
1个回答
1
投票

因为这是一个座位选择,更好的方法是定义一个对象数组,用 x, yselected 属性,就可以直接在模板中切换,而无需使用任何事件处理程序。然后,它可以直接在模板中切换,而无需使用任何事件处理程序。请尝试下面的方法

控制器

export class ClickSVGComponent implements OnInit {
  public seats: Array<Array<{x: number, y: number, selected: boolean}>> = [];
  range = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

  public toggleStyle: boolean = false;

  constructor() {
    for (let i = 0; i < 10; i++) {
      this.seats[i] = [];
      for (let j = 0; j < 10; j++) {
        this.seats[i].push({x: (i * 10), y: (j * 10), selected: false});
      }
    }
  }

  ngOnInit() {
  }
}

模板

<svg width="210mm" height="297mm" version="1.1" viewBox="0 0 210 297" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">

  <g>
    <ng-container *ngFor="let i of range">
      <ng-container *ngFor="let j of range">
        <rect 
          [attr.fill]="seats[i][j].selected ? 'red': ''"      <!-- use ternary operator to set the fill value -->
          id="{{i}}{{j}}a" 
          [attr.x]="seats[i][j].x" 
          [attr.y]="seats[i][j].y" 
          width="8" 
          height="8" 
          (click)="seats[i][j].selected = !seats[i][j].selected"
        />
      </ng-container>
    </ng-container>
  </g>
</svg>

我已经修改了你的 叠加闪电战

更新:最大选择条件

我改变了对象结构,引入了一个叫 maxSelected boolean,表示是否达到了最大选择数。检查条件的多个数组 maps和一个数组 concat 是应用在 counter() 点击事件的事件处理程序。

理解它的最快方法是剖析条件并观察每个语句的输出。这是一个相当直接的条件,写成一条语句。

模板也是针对条件进行调整的。我们需要允许重选,如果 maxReached 又被设置为 false.

控制器

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

export const MAX_SELECTION = 9;       // <-- max no. of seats allowed to select

interface Seats {       // <-- a collection of seats
  maxReached: boolean,
  attr: Array<Array<Attribute>>   // array of array - `x` denotes the row, `y` denotes the column
}

interface Attribute {    // <-- properties of each seat
  x: number,
  y: number,
  selected: boolean
}

@Component({
  selector: 'app-click-svg',
  templateUrl: './click-svg.component.html',
  styleUrls: ['./click-svg.component.css']
})
export class ClickSVGComponent implements OnInit {
  public seats: Seats = {maxReached: false, attr: []};
  range = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

  public toggleStyle: boolean = false;

  constructor() {
    for (let i = 0; i < 10; i++) {     // <-- loop through row of seats
      this.seats.attr[i] = [];         // <-- each row is initially empty
      for (let j = 0; j < 10; j++) {   // <-- loop through each seat of the row
        this.seats.attr[i].push({x: (i * 10), y: (j * 10), selected: false});
        //                          ^             ^           ^
        //                          |             |           |
        // use row value to set x ---             |           |
        // use coloum value to set y coord. -------           |
        // by default the seat is not selected ----------------
      }
    }
  }

  ngOnInit() {
  }

  counter() {
    /* 
    Do the following to understand what each statement does

    const seatsAll = this.seats.attr.map(row => { 
      console.log('row': row)
      row.map(seat => {
        console.log('seat': seat);
        seat.selected;
      })
    })
    console.log('all seats': seatsAll);
    const seatsSelectedConcat = [].concat.apply([], seatsAll);
    console.log('all seats single array': seatsSelectedConcat);
    const seatsSelectedTrue = seatsSelectedConcat.filter(status => status);
    console.log('all seats single array': seatsSelectedTrue);
    */

    const selected = (
      [].concat.apply([], (         // <-- output (Array(100)): [true, false, true, false, true,...]
        this.seats.attr.map(        // <-- output (Array<Array(10)>(10)): [[true, false...], [false, true,...], ...]  
          row => row.map(
            seat => seat.selected   // <-- output (Array(10)): [true, false, true...]  
          )
        )
      ))
    )
    .filter(status => status)       // <-- output only true: [true, true, true]
    .length;                        // <-- number of seats selected
    
    if (selected === MAX_SELECTION) {
      this.seats.maxReached = true;
    } else {
      this.seats.maxReached = false;
    }
  }
}

模板

<p>
  Please select a maximum of 9 seats. <br>
  <span style="color: red" *ngIf="seats.maxReached">
    Maximum number of seats selected.
  </span>
</p>

<svg width="210mm" height="297mm" version="1.1" viewBox="0 0 210 297" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">

  <g>
    <ng-container *ngFor="let i of range">        <!-- same loop as the controller - row -->
      <ng-container *ngFor="let j of range">      <!-- column -->
        <rect 
          [attr.fill]="seats.attr[i][j].selected ? 'red': ''" 
          id="{{i}}{{j}}a" 
          [attr.x]="seats.attr[i][j].x" 
          [attr.y]="seats.attr[i][j].y" 
          width="8" 
          height="8"
          (click)="
            seats.attr[i][j].selected ?           
              seats.attr[i][j].selected = !seats.attr[i][j].selected :     <!-- if seat selected already deselect it --> 
              !seats.maxReached ?
                seats.attr[i][j].selected = !seats.attr[i][j].selected :   <!-- selected unselected seat only if max condition `false` -->
                '';                                                        <!-- don't select the seat if max condition `true` -->
            counter()" 
        />
      </ng-container>
    </ng-container>
  </g>
</svg>

更新 叠加闪电战


1
投票

你必须使用 fill 来改变一个svg矩形的颜色。

<rect [style.fill]="toggleColor()" (click)="toggleStyle = !toggleStyle;"></rect>

你也可以使用属性绑定。

<rect [attr.fill]="toggleColor()" (click)="toggleStyle = !toggleStyle;"></rect>

属性绑定不起作用,因为svg的属性并不反映在元素上的属性上,所以svg的绑定发生在元素上。[attr.*] 记法

实例

你也可以考虑设置一个属性,而不是调用一个函数来获取当前的颜色。之所以要调用两次函数,是因为angular在开发模式下运行,并进行了两次变化检测的调用,以确保第一轮之后没有任何变化

© www.soinside.com 2019 - 2024. All rights reserved.