我正在尝试制作一个交互式座位地图,如果您单击座位,它会改变其颜色。我找到了一些解决方案,但它们不起作用。
我有 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 "";
}
}
}
正如您在堆栈闪电战中看到的那样 - 这不会为矩形添加颜色。此外,该函数运行两次,因为它是元素的一部分。
斯塔克闪电战
感谢您对如何解决此问题的任何建议!
由于这是一个座位选择,更好的方法是定义一个具有x
、y
和selected
属性的对象数组。然后可以直接在模板中切换它,而无需使用任何事件处理程序。尝试以下操作
控制器
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()
事件处理程序中应用多个数组map
s 和一个数组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 在开发模式下运行,并执行两次更改检测调用以确保在第一轮之后没有任何更改。