简体   繁体   English

Angular 2 - 点击更改图标

[英]Angular 2 - Change icon on click

I have a materialize collapsible list in my angular2 application. 我在angular2应用程序中有一个实现可折叠列表。 What I want to do, is change the icon of the list item when someone clicks on it. 我想要做的是,当有人点击它时,更改列表项的图标。 So far I attached a click event onto the list. 到目前为止,我将一个click事件附加到列表中。 When I print this out to the console, I see the element reference. 当我将其打印到控制台时,我看到了元素参考。 So I'm able to look down the child nodes and find the li element that has the active class attached to it. 所以我能够查看子节点并找到附加了活动类的li元素。 My thinking is that once I find the active element I can just change the child node's icon to the new one. 我的想法是,一旦找到活动元素,我就可以将子节点的图标更改为新图标。 This way I don't change all the icons. 这样我就不会改变所有的图标。 However, when I try to set the icon to the new icon, I get TypeError: 0 is read-only . 但是,当我尝试将图标设置为新图标时,我得到TypeError: 0 is read-only Does anyone know how to do this via angular 2? 有没有人知道如何通过角度2做到这一点?

Plunker Plunker
https://plnkr.co/edit/jQWf7uIRZIwr4fhyFT03?p=preview https://plnkr.co/edit/jQWf7uIRZIwr4fhyFT03?p=preview

List 名单

  <ul class="collapsible" data-collapsible="accordion">
    <li>
      <div class="collapsible-header"><i class="material-icons">filter_drama</i>First</div>
      <div class="collapsible-body"><span>Lorem ipsum dolor sit amet.</span></div>
    </li>
    <li>
      <div class="collapsible-header"><i class="material-icons">place</i>Second</div>
      <div class="collapsible-body"><span>Lorem ipsum dolor sit amet.</span></div>
    </li>
    <li>
      <div class="collapsible-header"><i class="material-icons">whatshot</i>Third</div>
      <div class="collapsible-body"><span>Lorem ipsum dolor sit amet.</span></div>
    </li>
  </ul>

Desired Behavior: Basically I'm trying to make a drop down tree using materlize collapsible list. 期望的行为:基本上我正在尝试使用materlize可折叠列表制作下拉树。 So you click on an item it changes its icon from a plus sign to a minus sign to simulate that you are expanding and contracting the item. 因此,您单击某个项目,将其图标从加号更改为减号,以模拟您正在扩展和收缩该项目。

Picture Example Link 图片示例链接

Angular only solution (no jQuery needed) Angular only解决方案(不需要jQuery)

You can simply toggle between two icons using a variable that you change on click: 您可以使用在单击时更改的变量在两个图标之间切换:

<div class="collapsible-header" (click)="showFirst=!showFirst"><i class="material-icons" *ngIf="showFirst">filter_drama</i><i class="material-icons" *ngIf="!showFirst">place</i>First Section</div>

If you want only to hide the icon, you do it the same way with only one icon: 如果您只想隐藏图标,只需使用一个图标即可:

<div class="collapsible-header" (click)="showSecond=!showSecond"><i class="material-icons" *ngIf="!showSecond">place</i>Second Section</div>

I forked your plunker and edited the changes here 我分叉你的plunker并在这里编辑了变化

PS: On your plunker you were loading material icons from a http url, making chrome to refuse to load the resource. PS:在您的plunker上,您正在从http url加载材质图标,使chrome拒绝加载资源。 Change the url to https and it will work. 将网址更改为https ,它将工作。

Edit 编辑

@Judson Terrell - for me, Angular only solution looks cleaner @Judson Terrell - 对我而言,Angular唯一解决方案看起来更干净

Angular only 只有角度

<div class="collapsible-header" (click)="!show=show"><i class="material-icons" *ngIf="show">filter_drama</i>First</div>

Angular + jQuery Angular + jQuery

html HTML

<div class="collapsible-header" id="clickedId"><i class="material-icons" id="someId">filter_drama</i>First</div>

js JS

$( "#clickedId" ).click(function() {
  $("#someId").toggleClass('someIconClass');
});

+ jQuery lib - and the presumable performance problems it induces + jQuery lib - 以及它引发的可能的性能问题

Edit2 - after clearing the question Edit2 - 清除问题后

What you want is achievable using CSS only: 您想要的只能使用CSS实现:

html: HTML:

<div class="collapsible-header"><i class="material-icons more">expand_more</i><i class="material-icons less">expand_less</i>First Section</div>

css: CSS:

.collapsible-header.active i.more{
display:none;
}

.collapsible-header.active i.less{
display:block;
}

.collapsible-header i.less{
display:none;
}

Updated plunker here 这里更新了plunker

Credit for idea to this answer 相信这个答案的想法

I would recommend toggling a class change based on the icon you want to add or remove someIcon class on the i tag. 我建议根据您要添加的图标切换类更改,或者删除i标签上的someIcon类。

In jQuery it's 在jQuery中它是

$(el).toggleClass('someIconClass')

I personally have not had much luck with elementRef etc in Angular 4 and have resorted to putting jQuery in my apps. 我个人对Angular 4中的elementRef等没有太多运气,并且已经在我的应用程序中使用了jQuery。 Just a suggestion (not best practice I am sure someone will argue) 只是一个建议(不是最佳实践,我相信有人会争辩)

I peeked at the code for Angular materialize, and it appears its a sort of angular 'shim' that uses jQuery and some other workarounds to make this CSS/JS framework work properly in Angular 2. That makes something like what you want a little trickier than it would be if it was pure Angular 2. 我偷看了Angular materialize的代码,看起来它是一种有角度的“垫片”,它使用jQuery和其他一些解决方法来使这个CSS / JS框架在Angular 2中正常工作。这就像你想要的东西有点棘手比它纯粹的Angular 2还要好。

The 'Angular way', would be to have each menu item a separate component that keeps track of its own state. 'Angular方式',是让每个菜单项都是一个单独的组件,用于跟踪自己的状态。 It would keep track of whether its expanded or collapsed, and it could even output an event based on that state, which would make changing the icon trivial. 它会跟踪它是展开还是折叠,甚至可以输出基于该状态的事件,这会使图标变得微不足道。 It could even keep track of the number of times its been clicked and slowly change colors as its clicked more and more. 它甚至可以跟踪点击的次数,并随着点击次数的增加而慢慢改变颜色。 Stuff like that is really easy when everything is encapsulated in its own component. 当一切都封装在自己的组件中时,这样的东西真的很容易。

In lieu of that you'll have to manage the menu states manually, using something like an array of booleans. 取而代之的是,你必须手动管理菜单状态,使用类似布尔数组的东西。 The problem with this is that you'll have 2 separate view states managed in different places for the same thing - and they may not always be in sync. 这样做的问题在于,您将在不同的地方为同一事物管理2个单独的视图状态 - 并且它们可能并不总是同步。 One in the component for your icons, and one in ... wherever that materialize code is coming from ... The materialize code may be using a CSS :active selector to change something on click, and you may use a (click) handler in Angular to change something on a click, and those 2 things aren't always guaranteed to be in sync for a number of reasons. 一个在你的图标的组件中,一个在...实现代码的任何地方来自...实现代码可能使用CSS:主动选择器来更改点击的东西,你可以使用(点击)处理程序在Angular中,可以在点击时更改某些内容,但由于多种原因,这些内容并不总是保证同步。 So if they ever get out of sync the icons will be backwards and it will be hard to fix. 因此,如果他们不同步,图标将会倒退,并且很难修复。

In fact, this may be a situation where it actually is easier to use jQuery from within Angular, simply bc the technology you are working with uses jQuery as well. 事实上,这可能是一种情况,它实际上更容易使用jQuery从内部角度,只需BC你正在使用的技术使用jQuery的为好。

But if you reaalllly want it to work in Angular using this framework, here's how you could do it, just be forewarned that it will be very fragile. 但是如果你真的希望它使用这个框架在Angular中工作,那么你可以做到这一点,只是预先警告它会非常脆弱。

I would create an array of objects in your component that represented the menu. 我会在组件中创建一个表示菜单的对象数组。 Each object could hold its menu text, expanded text, and a boolean representing its expanded/collapsed state. 每个对象都可以保存其菜单文本,扩展文本和表示其展开/折叠状态的布尔值。

You could define an interface outside the component to give you type checking on this if you wanted. 您可以在组件外部定义一个接口,以便在需要时对其进行类型检查。

import { Component } from '@angular/core'

export interface CollapsibleItem { 
    label: string; 
    text: string;
    state: boolean;
}

@Component({
selector:'whateveryouwant',
template: `

<ul class="collapsible" data-collapsible="accordion">
    <li *ngFor="let item of menuItems; let i = index" (click)="menuClick(i)">
       <div class="collapsible-header">
         <i class="material-icons" *ngIf="item.state"> minus-icon </i>
         <i class="material-icons" *ngIf="!item.state"> plus-icon </i>
         {{ item.label }} 
       </div>
       <div class="collapsible-body">
         <span> {{ item.text }} </span>
       </div>
    </li>
`,
styles: ['']  
})

export class YourComponentName {

   constructor() {  }  

    menuItems: CollapsibleItem[] = [
    { label: 'First', text: 'Lorem Ipsum', state: false },
    { label: 'Second', text: 'Lorem Ipsum', state: false },
    { label: 'Third', text: 'Lorem Ipsum', state: false },
   ];

    menuClick(clickedItem: number) {
        this.menuItems[clickedItem].state = !this.menuItems[clickedItem].state  // flips the boolean value for the clicked item 
        for (let item of this.menuItems) {  
           if ( item !== this.menuItems[clickedItem] ) { 
               item.state = false; 
           }
        }
        // the for loop goes through the array and sets each item to false *if* its not the item that was clicked
     }   
 }

See... by the time you get this working in Angular, you probably could have just built your own menu item components which would be easier to work with and far more scaleable :) You're creating an array of objects with several different properties per object and trying to manage them with each click. 看看......当你在Angular中使用它时,你可能刚刚构建了自己的菜单项组件,这些组件更易于使用且更具可扩展性:)你正在创建一个具有多个不同属性的对象数组每个对象并尝试通过每次单击来管理它们。 This is why components were created! 这就是创建组件的原因! You could create a simple wrapper component for each item, but I'm not sure how that would work since the materialize thing is using jQuery and CSS to select for stuff. 你可以为每个项目创建一个简单的包装器组件,但是我不确定它是如何工作的,因为实体化的东西是使用jQuery和CSS来选择东西。 It might be unpredictable using normal component view encapsulation. 使用普通组件视图封装可能无法预测。

An alternative to switching out the icons with ngIf would be binding to the innerText property, and switching the text based on the state. 使用ngIf切换图标的替代方法是绑定到innerText属性,并根据状态切换文本。

<i class="material-icons"  [innerText]="item.state ? 'plus-icon' : 'minus-icon'"></i>

But I'm not sure if the materialize framework would pick up on the changes to the innerText quickly or at all. 但是我不确定物化框架是否会快速或完全接受对innerText的更改。 Better to have both render, and switch between them, if you're trying to mix technologies like this. 如果你想尝试混合这样的技术,最好同时渲染,并在它们之间切换。

Also, i have no idea if 'plus-icon' or 'minus-icon' are how you would refer to those icons, but you probably get the point :p 另外,我不知道'plus-icon'或'minus-icon'是如何引用这些图标的,但你可能会明白这一点:p

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM