Angular 2 - 点击更改图标

时间:2017-08-23 02:54:49

标签: javascript angular materialize

我在angular2应用程序中有一个materialize可折叠列表。我想要做的是,当有人点击它时,更改列表项的图标。到目前为止,我将一个click事件附加到列表中。当我将其打印到控制台时,我看到了元素参考。所以我能够查看子节点并找到附加了活动类的li元素。我的想法是,一旦找到活动元素,我就可以将子节点的图标更改为新图标。这样我就不会改变所有的图标。但是,当我尝试将图标设置为新图标时,我得到TypeError: 0 is read-only。有没有人知道如何通过角度2来做到这一点?

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

列表

  <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>

所需行为: 基本上我正在尝试使用materlize可折叠列表制作下拉树。因此,您单击某个项目,将其图标从加号更改为减号,以模拟您正在扩展和收缩该项目。

Picture Example Link

3 个答案:

答案 0 :(得分:6)

只有Angular的解决方案(不需要jQuery)

您可以使用您在点击时更改的变量在两个图标之间切换:

    class Program
{
    static void Main(string[] args)
    {
        Mapper.Initialize(MapperConfiguration);

        var parent = new Parent()
        {
            Id = "a",
            Child = new Child()
            {
                Name = "ChildA",
                Id = 1
            }
        };

        var child = Mapper.Map<Child>(parent);

        Console.Read();
    }

    private static void MapperConfiguration(IMapperConfigurationExpression mapper)
    {
        mapper.CreateMap<Parent, Child>()
            .ProjectUsing(x => x.Child);
    }

    public class Parent
    {
        public string Id { get; set; }
        public Child Child { get; set; }
    }

    public class Child
    {
        public string Name { get; set; }
        public int Id { get; set; }
    }
}

如果您只想隐藏图标,只需使用一个图标即可:

<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>

我分叉你的plunker并编辑了变化here

PS:在您的plunker上,您正在从<div class="collapsible-header" (click)="showSecond=!showSecond"><i class="material-icons" *ngIf="!showSecond">place</i>Second Section</div> 网址加载材质图标,使Chrome无法加载资源。将网址更改为http即可。

修改

@Judson Terrell - 对我来说,Angular唯一的解决方案看起来更干净

仅限角度

https

Angular + jQuery

<强> HTML

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

<强> JS

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

+ jQuery lib - 以及它引发的可能出现的性能问题

Edit2 - 清除问题后

您想要的只能使用CSS实现:

HTML:

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

的CSS:

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

更新了plunker here

归功于this answer

答案 1 :(得分:0)

我建议您根据要添加的图标切换课程更改,或删除someIcon标记上的i课程。

在jQuery中它是

$(el).toggleClass('someIconClass')

我个人对Angular 4中的elementRef等运气不太好,并且已经在我的应用程序中使用了jQuery。只是一个建议(不是最佳实践,我相信有人会争辩)

答案 2 :(得分:0)

我偷看了Angular materialize的代码,看起来它是一种有角度的“垫片”,它使用jQuery和其他一些解决方法来使这个CSS / JS框架在Angular 2中正常工作。这就像你想要的那样如果它是纯粹的Angular 2,会有点棘手。

'Angular方式',是让每个菜单项都有一个单独的组件来跟踪它自己的状态。它会跟踪它是展开还是折叠,甚至可以输出基于该状态的事件,这会使图标变得微不足道。它甚至可以跟踪点击的次数,并随着点击次数的增加而慢慢改变颜色。当一切都封装在自己的组件中时,这样的东西真的很容易。

除此之外,你必须手动管理菜单状态,使用类似布尔数组的东西。这样做的问题在于,您将在不同的地方为同一事物管理2个单独的视图状态 - 并且它们可能并不总是同步。一个在你的图标的组件中,一个在...实现代码的任何地方来自...实现代码可能使用CSS:主动选择器来更改点击的东西,你可以使用(点击)处理程序在Angular中,可以在点击时更改某些内容,但由于多种原因,这些内容并不总是保证同步。因此,如果他们不同步,图标将会倒退,并且很难修复。

事实上,这可能是 更容易在Angular中使用jQuery的情况,简单地说,您正在使用的技术也使用jQuery。

但是,如果你真的想让它在Angular中使用这个框架,那么你可以做到这一点,只需要预先知道它会非常脆弱。

我会在组件中创建一个表示菜单的对象数组。每个对象都可以保存其菜单文本,扩展文本和表示其展开/折叠状态的布尔值。

您可以在组件外部定义一个接口,以便根据需要对其进行类型检查。

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
     }   
 }

看看......当你在Angular中使用它时,你可能刚刚构建了自己的菜单项组件,这些组件更易于使用且更具可扩展性:)你正在创建一个对象数组每个对象有几个不同的属性,并尝试通过每次单击来管理它们。这就是创建组件的原因!你可以为每个项目创建一个简单的包装器组件,但是我不确定它是如何工作的,因为实体化的东西是使用jQuery和CSS来选择东西。使用普通组件视图封装可能无法预测。

使用ngIf切换图标的替代方法是绑定到innerText属性,并根据状态切换文本。

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

但是我不确定物化框架是否会快速或完全接受对innerText的更改。如果你想尝试混合这样的技术,最好同时渲染和切换它们。

此外,我不知道'plus-icon'或'minus-icon'是如何引用这些图标的,但你可能会明白这一点:p