web-dev-qa-db-ja.com

Angular 2-クリックでアイコンを変更

私のangular2アプリケーションにマテリアライズ折りたたみ可能なリストがあります。私がやりたいことは、誰かがクリックしたときにリストアイテムのアイコンを変更することです。これまでのところ、リストにクリックイベントをアタッチしました。これをコンソールに出力すると、要素の参照が表示されます。したがって、子ノードを調べて、アクティブなクラスが関連付けられているli要素を見つけることができます。私の考えでは、アクティブな要素を見つけたら、子ノードのアイコンを新しいものに変更するだけです。この方法では、すべてのアイコンを変更するわけではありません。しかし、アイコンを新しいアイコンに設定しようとすると、TypeError: 0 is read-only。 angular 2を介してこれを行う方法を誰かが知っていますか?

プランカー
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の折りたたみ可能なリストを使用してドロップダウンツリーを作成しようとしています。したがって、アイテムをクリックすると、そのアイコンがプラス記号からマイナス記号に変わり、アイテムを拡大および縮小していることをシミュレートします。

画像例リンク

5
AJ_

角度のみのソリューション(jQueryは不要)

クリックで変更する変数を使用して、2つのアイコンを簡単に切り替えることができます。

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

アイコンを非表示にするだけの場合は、アイコンを1つだけ使用して同じようにします。

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

私はあなたのプランカーをフォークして変更を編集しました ここ

PS:プランカーでhttp urlからマテリアルアイコンをロードしていて、chromeがリソースのロードを拒否するようにしました。URLをhttpsに変更すると、動作します。

編集する

@ジャドソンテレル-私にとって、Angularソリューションのみがきれいに見える

角度のみ

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

Angular + jQuery

html

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

js

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

+jQuery lib-およびそれが引き起こす推定パフォーマンスの問題

Edit2-質問をクリアした後

あなたが望むものはCSSのみを使用して達成できます:

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:

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

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

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

更新されたプランカー ここ

アイデアのクレジット この答え

9
BogdanC

someIconタグでiクラスを追加または削除するアイコンに基づいて、クラスの変更を切り替えることをお勧めします。

JQueryでは

$(el).toggleClass('someIconClass')

私は個人的には、Angular 4)のelementRefなどにあまり慣れておらず、jQueryを自分のアプリに配置することに頼っています。 )

0
Judson Terrell

私はAngular materializeのコードをのぞいて、jQueryと他のいくつかの回避策を使用してこのCSSを作成するangular 'shim'のように見えます/ JSフレームワークはAngular 2.で適切に機能します。これにより、純粋な場合よりも少し複雑になります。Angular 2。

「角度のある方法」では、各メニュー項目を、独自の状態を追跡する個別のコンポーネントにすることになります。展開されているか折りたたまれているかを追跡し、その状態に基づいてイベントを出力することもできるため、アイコンの変更は簡単です。クリックされた回数を追跡し、クリックが増えるにつれてゆっくりと色を変えることもできます。そのようなものは、すべてが独自のコンポーネントにカプセル化されている場合、本当に簡単です。

その代わりに、ブール値の配列のようなものを使用して、手動でメニューの状態を管理する必要があります。これの問題は、同じものに対して異なる場所で管理される2つの個別のビューステートがあり、常に同期しているとは限らないことです。 1つはアイコンのコンポーネントにあり、もう1つは...マテリアライズコードがどこから来ているのか...マテリアライズコードはCSS:activeセレクターを使用してクリック時に何かを変更している場合があり、(クリック)ハンドラーを使用している場合があります。 Angularクリックで何かを変更する場合、これら2つの事柄は、いくつかの理由で常に同期しているとは限りません。したがって、同期が取れなくなった場合、アイコンは逆になりますそしてそれは修正するのが難しいでしょう。

実際、これは実際にis 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

0
diopside