在 Angular 中打开(单击)的样式绑定



我正在尝试制作一个交互式座位地图,如果您单击座位,它会改变其颜色。我找到了一些解决方案,但它们不起作用。

我有 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 "";
}
} 

}

正如您在堆栈闪电战中看到的那样 - 这不会为矩形添加颜色。此外,该函数运行两次,因为它是元素的一部分。

斯塔克闪电战

感谢您对如何解决此问题的任何建议!

由于这是一个座位选择,更好的方法是定义一个具有xyselected属性的对象数组。然后可以直接在模板中切换它,而无需使用任何事件处理程序。尝试以下操作

控制器

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布尔值,该布尔值表示是否已达到最大选择数。若要检查条件,请在单击事件的counter()事件处理程序中应用多个数组maps 和一个数组concat

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

模板也会根据条件进行调整。如果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 column 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>

更新的堆栈闪电战

您必须使用fill来更改 svg 矩形的颜色。

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

您还可以使用属性绑定:

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

属性绑定不起作用,因为 svg 的属性不会反映为元素上的属性,因此 svg 上的绑定使用[attr.*]表示法进行

工作示例

您还可以考虑设置属性,而不是调用函数来获取当前颜色。它调用该函数两次的原因是因为 angular 在开发模式下运行,并执行两次更改检测调用以确保在第一轮之后没有任何更改。

最新更新