Search code examples
angularangular2-components

On/Off FlipSwitch in CSS not working as an Angular 2 Component


I am trying to create a re-usable flip switch component as

import { Component, Input } from "@angular/core";

@Component({
    selector: "bm-input-switch",
    templateUrl: "./bm-input-switch.component.html",
    styleUrls:['bm-input-switch.component.css']
})
export class BmInputSwitchComponent {

    @Input()
    name: string;

    @Input()
    id: string;

    @Input()
    labelText: string;

    @Input()
    checked :boolean;
}

HTML bm-input-switch.component.html:

<div>
    <div class="onoffswitch">
        <input type="checkbox" [name]="name" class="onoffswitch-checkbox" [id]="id">
        <label class="onoffswitch-label" [for]="id">
            <span class="onoffswitch-inner"></span>
            <span class="onoffswitch-switch"></span>
        </label>
    </div>
</div>

CSS bm-input-switch.component.css

.onoffswitch {
    position: relative;
    width: 90px;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
}

.onoffswitch-checkbox {
    display: none;
}

.onoffswitch-label {
    display: block;
    overflow: hidden;
    cursor: pointer;
    border: 2px solid #999999;
    -ms-border-radius: 20px;
    border-radius: 20px;
}

.onoffswitch-inner {
    display: block;
    width: 200%;
    margin-left: -100%;
    -ms-transition: margin 0.3s ease-in 0;
    -o-transition: margin 0.3s ease-in 0;
    -webkit-transition: margin 0.3s ease-in 0;
    transition: margin 0.3s ease-in 0;
}

    .onoffswitch-inner:before, .onoffswitch-inner:after {
        display: block;
        float: left;
        width: 50%;
        height: 30px;
        padding: 0;
        line-height: 30px;
        font-size: 14px;
        color: white;
        font-family: Trebuchet, Arial, sans-serif;
        font-weight: bold;
        -moz-box-sizing: border-box;
        box-sizing: border-box;
    }

    .onoffswitch-inner:before {
        content: "YES";
        padding-left: 10px;
        background-color: #1C456B;
        color: #FFFFFF;
    }

    .onoffswitch-inner:after {
        content: "NO";
        padding-right: 10px;
        background-color: #EEEEEE;
        color: #999999;
        text-align: right;
    }

.onoffswitch-switch {
    display: block;
    width: 27px;
    margin: 1.5px;
    background: #FFFFFF;
    position: absolute;
    top: 0;
    bottom: 0;
    right: 56px;
    border: 2px solid #999999;
    -ms-border-radius: 20px;
    border-radius: 20px;
    -ms-transition: all 0.3s ease-in 0;
    -o-transition: all 0.3s ease-in 0;
    -webkit-transition: all 0.3s ease-in 0;
    transition: all 0.3s ease-in 0;
}

.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-inner {
    margin-left: 0;
}

.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-switch {
    right: 0px;
}

USAGE

<bm-input-switch id="gaVersion" name="gaVersion" labelText="GA Version" checked="false"></bm-input-switch>

However, it is not changing the state on click. If I do not use it as component and just try to run in static page, it then works.

Any Ideas ? Plunker : https://plnkr.co/edit/hdNI02Eywx1xsHTn9tSA?p=preview


Solution

  • Your input variables on the switch component are confusing the "for" attribute. If you look at the generated html, you'll have two elements with the same id. Also, don't use the square brackets for native DOM attributes, just use the curly braces.

    Check out this new plnkr with a working switch. https://plnkr.co/edit/isecXgfkU3K93GIxtviP?p=preview

    I've just changed your "id" and "name" variables to "switchId" and "switchName", and also changed the [id] and [name] bindings to use curly brackets inside your switch component html.

    Your new switch component:

    import { Component, Input } from "@angular/core";
    
    @Component({
        selector: "bm-input-switch",
        templateUrl: "bm-input-switch.component.html",
        styleUrls:['bm-input-switch.component.css']
    })
    export class BmInputSwitchComponent {
    
        @Input()
        switchName: string;
    
        @Input()
        switchId: string;
    
        @Input()
        labelText: string;
    
        @Input()
        checked :boolean;
    }
    

    Your switch component html:

    <div>
      <div>{{labelText}}</div>
      <div class="onoffswitch">
        <input type="checkbox" name="{{switchName}}" class="onoffswitch-checkbox" id="{{switchId}}">
        <label class="onoffswitch-label" for="{{switchId}}">
          <span class="onoffswitch-inner"></span>
          <span class="onoffswitch-switch"></span>
        </label>
      </div>
    </div>
    

    And calling it:

    <h1>Switch Example</h1>
    <div>
       <bm-input-switch switchId="autoCreate" switchName="autocreate" labelText="Auto Create" checked="false"></bm-input-switch>
    </div>
    
    <bm-input-switch switchId="displayCode" switchName="displayCode" labelText="Display Code" checked="false"></bm-input-switch>