Why isn't the Angular directive resolving the dynamic button text variable?

Trying to implement an iPhone-style Toggle Button using CSS in Angular.

The issue I am facing is that the dynamic button text variable "{{v1['btn2']}}" is not being evaluated properly the first time, although it works fine with static text.

URL for the jsFiddle example:

http://jsfiddle.net/vishalvasani/z5SNc/3/

Here is the provided code:

angular.module('test').controller('myctrl', function($scope){
    $scope.v1={
        "status":"1",
        "btn1":"On",
        "btn2":"Off"
    }
     $scope.v2={
        "status":"1"
     }
});

angular.module('test').directive('btnSwitch', function(){

  return {
    restrict : 'AE',
    require :  'ngModel',
    link : function(scope, element, attrs, ngModel){
        ngModel.$render = function() {
          render();
        };

        var render=function(){
          var val = ngModel.$viewValue; 
          var open=angular.element(element.children()[0]);
          var closed=angular.element(element.children()[1]);
          
          if(val)
          {
            closed.html(closed.attr("text"));
            closed.addClass('btnOnSelected');  
            open.html(" ");
            open.removeClass('btnOffSelected');  
          }
          else{
              open.html(open.attr("text")); 
              open.addClass('btnOffSelected');  
              closed.removeClass('btnOnSelected');  
              closed.html(" ");
          }
        };

        element.bind('click', function() {
          scope.$apply(toggle);             
        });

        function toggle() {
           var val = ngModel.$viewValue;
           ngModel.$setViewValue(!val); 
           render();          
        } 

        if(!ngModel){  
          return;          
        }  

         render();
    }
  };
});

HTML:

<div ng-app="test">
    <div ng-controller="myctrl">
        <div class="pull-left" btn-switch ng-model="v1['status']">
            <div class="pull-left btnCS btnOff" text="{{v1['btn1']}}">&nbsp;</div>
            <div class="pull-left btnCS btnOn btnOnSelected" text="{{v1['btn2']}}"></div>
        </div>
        <div class="clearFix" style="height:20px"></div>
        <hr />
         <div class="pull-left" btn-switch ng-model="v2['status']">
            <div class="pull-left btnCS btnOff" text="On">&nbsp;</div>
            <div class="pull-left btnCS btnOn btnOnSelected" text="Off"></div>
        </div>
    </div>
</div>

Answer №1

It appears that initializing the value is necessary the first time around. Check out the updated fiddle here: http://jsfiddle.net/sHZdg/.

At the end of your directive, I included these two lines of code:

var val = ngModel.$viewValue;
ngModel.$setViewValue(val);

These lines will set the initial value before calling render() to establish the values in the $scope.

Answer №2

Upon the initial execution of the directive, the attributes remain uninterpolated.

It is recommended to utilize $eval instead of {{}}s:

<div class="pull-left btnCS btnOff" text="v1['btn1']">&nbsp;</div>
<div class="pull-left btnCS btnOn btnOnSelected" text="v1['btn2']"></div>

closed.html(scope.$eval(closed.attr("text")));
...
open.html(scope.$eval(open.attr("text")));

fiddle

Answer №3

Upon initial execution of the directive, the attributes remain uninterpolated.

The recommended solution involves utilizing $timeout

Refer to the following jsfiddle for a functional demo:

View Demo

HTML Section

<div ng-app="test">
    <div ng-controller="myctrl">
        <div class="pull-left" btn-switch ng-model="v1['status']">
            <div class="pull-left btnCS btnOff" text="{{v1['btn1']}}">&nbsp;</div>
            <div class="pull-left btnCS btnOn btnOnSelected" text="{{v1['btn2']}}"></div>
        </div>
        <div class="clearFix" style="height:20px"></div>
        <hr />
         <div class="pull-left" btn-switch ng-model="v2['status']">
            <div class="pull-left btnCS btnOff" text="On">&nbsp;</div>
            <div class="pull-left btnCS btnOn btnOnSelected" text="Off"></div>
        </div>
    </div>
</div>

Controller Implementation:

angular.module('test', []);
angular.module('test').controller('myctrl', function($scope){
    $scope.v1={
        "status":"1",
        "btn1":"On",
        "btn2":"Off"
    }
     $scope.v2={
        "status":"1"
     }
});

Directive Implementation:

angular.module('test').directive('btnSwitch', function($timeout){

  return {
    restrict : 'AE',
    require :  'ngModel',
    link : function(scope, element, attrs, ngModel){


        ngModel.$render = function() {
          render();
        };

        var render=function(){
          var val = ngModel.$viewValue; 
            console.log(val);          
          var open=angular.element(element.children()[0]);

          var closed=angular.element(element.children()[1]);
          if(val)
          {
            closed.html(closed.attr("text"));
            closed.addClass('btnOnSelected');  
            open.html("&nbsp;");
            open.removeClass('btnOffSelected');  
          }
          else{
              open.html(open.attr("text")); 
              open.addClass('btnOffSelected');  
              closed.removeClass('btnOnSelected');  
              closed.html("&nbsp;");
          }
        };


        element.bind('click', function() {
          scope.$apply(toggle);             
        });


        function toggle() {
           var val = ngModel.$viewValue;
           ngModel.$setViewValue(!val); 
           render();          
        } 

        if(!ngModel){  

          return;          
        }  
        //console.log(ngModel.$viewValue)
        $timeout(function(){
            //var val = ngModel.$viewValue;
            //ngModel.$setViewValue(val);
            render();
        }, 0);            
    }
  };
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Collapse or display div elements with jQuery - First close all other elements before opening the selected item

The Problem at Hand Currently, the script is expected to hide all elements with the "gallery-collapse" class and reveal the specific content based on the clicked link. However, sometimes multiple divs might appear simultaneously when switching between ite ...

Using a background image in a React component

Currently, I am working on a webpage and facing an issue while trying to set a background image for a Material UI element using the background-image CSS property. Despite researching online for solutions, I am unable to make the image appear. P.S.1: I eve ...

A comprehensive guide on utilizing the loading.tsx file in Next JS

In the OnboardingForm.tsx component, I have a straightforward function to handle form data. async function handleFormData(formData: FormData) { const result = await createUserFromForm( formData, clerkUserId as string, emailAddress a ...

Tips for centering content in the middle of a line

How can I center align 3 buttons on a line using CSS and HTML? This is what I have tried so far: 1/ CSS : .center-buttons { display: flex; justify-content: center; } .button { margin: 0 10px; } 2/ HTML: <div class="row"> <di ...

In which specific location within the Bootstrap CSS files can the `footer` class be found?

Being new to coding, I've grasped HTML and CSS classes and am now delving into Bootstrap. Despite my efforts, I can't seem to locate the footer class in any of the Bootstrap CSS files like bootstrap.css. Similarly, I'm having trouble findi ...

Error: Certain Prisma model mappings are not being generated

In my schema.prisma file, I have noticed that some models are not generating their @@map for use in the client. model ContentFilter { id Int @id @default(autoincrement()) blurriness Float? @default(0.3) adult ...

How can conditional types be implemented with React Select?

I am working on enhancing a wrapper for React-select by adding the capability to select multiple options My onChange prop is defined as: onChange: ( newValue: SingleValue<Option>, actionMeta: ActionMeta<Option>, ) => void Howev ...

Error: JSON parsing error encountered due to an unexpected token 'U' while trying to read a file with

Currently, I am utilizing Node.js version 12.14.1 and encountering a problem while attempting to parse a JSON file that includes the \U0001f970 character. The file's content that needs to be read and parsed is as follows: {"randomKey": ...

Utilizing constants with AngularJS for enhanced value manipulation

Is it feasible to define a new value in Angular by using existing values? For example, if I have two predefined values and want to create a third one based on the first two: angular.module('my.module').value('firstOne', ['John&apo ...

[filepond] in order to enroll using the serverId value received from the server

Using 'filepond' within a Vue application is causing an issue. In the "process" function, the ID value obtained after transferring the file to the server (response.id) needs to be registered as 'serverId' of the file. Upon checking the ...

Having trouble retrieving weather information from the JSON data with Angular

Is there an error in my parsing method? I'm attempting to retrieve weather data function Hello($scope, $http) { $http .jsonp('http://api.worldweatheronline.com/free/v1/weather.ashx?q=London&format=json&num_of_days=5&key=MYKEY& ...

Enabling the acceptance of blank values within an HTML5 date input field

When using an HTML5 date input for a field that corresponds to a nullable datetime column in the database, how can one avoid setting an empty value in the input field? In my AngularJS application, the ng-model is connected to a scope variable with an init ...

Optimizing Static File Caching in Yii

Having a frustrating issue with Yii where my local development environment caches CSS and JS files. Despite making changes to the file, the edits do not reflect in the output and sometimes causes corruption leading to broken functionality. This problem see ...

What is the best way to choose the current Div's ID, as well as its Width and Height properties?

Within this section, there are four div elements with varying widths, heights, and colors that appear and disappear when their respective buttons are clicked. I am adding an "activeDiv" class to the visible div in order to easily select it using that class ...

Creating a personalized Autocomplete feature using React Material-UI with the help of the renderInput method

I'm currently using a React Material UI Autocomplete component, similar to the one in the official documentation. For example, let's consider a list of countries: import * as React from 'react'; import Box from '@mui/material/Box& ...

Adding a block between two other blocks on a mobile device using Bootstrap 4

I am trying to achieve a specific layout on both desktop and mobile devices. On desktop, I want the layout to be structured as follows: [1][2] [3][2] The requirement is for column 2 to be the same height as columns 1 and 3 on desktop screens. For the mo ...

Transforming segments into divisions

I recently designed a website using sections instead of divs in order to achieve the desired alignment of the divs within the same container. However, I am facing difficulties and confusion in implementing this approach. Currently, my divs collapse on top ...

Creating an array of JSX elements or HTMLElements in a React TypeScript rendering

Currently in the process of developing a custom bootstrap card wrapper that allows for dynamic rendering of elements on the front and back of the card based on requirements. Here is the initial implementation: import React, { useState, ReactElement } from ...

Exploring the contrast of && and ?? in JavaScript

My current focus is on utilizing the Logical AND && and Nullish coalescing operator ?? in handling conditional rendering of variables and values. However, I find myself struggling to fully comprehend how these operators function. I am seeking clar ...

The transition effect of changing opacity from 0 to 1 is not functioning properly in Firefox

Having some trouble with this animation not working in Firefox. I'm triggering the animation using JavaScript after a delay like so: document.getElementById('my_id').style.webkitAnimationPlayState = "running"; I've also attempted: s ...