What is the best way to utilize a single AngularJS 1.5 component multiple times within a single view?

While working on a project using AngularJS 1.5's new components, I encountered an issue with widget isolation. It seems that when I use the same widget multiple times, they end up sharing their controller or scope. I was under the impression that components were supposed to have completely isolated scopes. What could be causing this?


Here is a snippet of my main html template where the widgets are placed:

<widget-list
    title="Books"
    class="col-xs-12 col-md-4">
</widget-list>

<widget-list
    title="Movies"
    class="col-xs-12 col-md-4">
</widget-list>

<widget-list
    title="Albums"
    class="col-xs-12 col-md-4">
</widget-list>

This is the structure of my widget template:

<div class="widget widget-list">
    <div class="panel b-a">

        <div class="panel-heading b-b b-light">
            <h5>{{$widget.title}}</h5>
            <div class="pull-right">
                <button type="button" class="btn btn-default btn-sm" ng-click="$widget.doSomething()">
                    Do something
                </button>
            </div>
        </div>

        <div class="panel-content">
            {{$widget.content || 'No content'}}
        </div>

    </div>
</div>

This is my widget component setup:

app.component('widgetList', {
    templateUrl: 'template/widget/widget-list.html',
    bindings: {
        title   : '@',
    },
    controllerAs: '$widget',
    controller: function($timeout) {

        $widget = this;

        console.log('Title on init: ', $widget.title)

        $timeout(function() {
            console.log('Title after 3 seconds: ', $widget.title)
        }, 3000)

        $widget.doSomething = function() {
            $widget.content = "Something";
        }
    }
});

Upon running my code, the console output is as follows:

Title on init: Books
Title on init: Movies
Title on init: Albums
(3) Title after 3 seconds: Albums

Additionally, after rendering, all three widgets display No content in their template. Oddly, when I click the doSomething() button in any widget, only the content of the last widget updates to Something. This behavior is confusing me. Why are my components not maintaining isolation as expected?

Answer №1

It appears that you are using a global variable named $widget in your code. To improve this, consider implementing the following:

var $widget = this;

Instead of:

$widget = this;

This change is beneficial as it will prevent any confusion in your code. The $widget variable will now correctly hold a reference to the initialized controller, specifically the controller of the third component.

Answer №2

Your code has a problem where the $widget is declared on the window scope, causing the controller to print the last value because it gets overridden each time the controller is instantiated. To resolve this issue, use var $widget instead and your code will function correctly.

Here is a snippet that fixes the issue:

angular.module('app', [])
  .component('widgetList', {
    templateUrl: 'template/widget/widget-list.html',
    bindings: {
      title: '@',
    },
    controllerAs: '$widget',
    controller: WidgetListController
  });

function WidgetListController($timeout) {

  var $widget = this;

  console.log('Title on init: ', $widget.title)

  $timeout(function() {
    console.log('Title after 3 seconds: ', $widget.title)
  }, 3000)

  $widget.doSomething = function() {
    $widget.content = "Something";
  }
}

angular.element(document).ready(function() {
  angular.bootstrap(document, ['app']);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.1/angular.min.js"></script>
<widget-list title="Books" class="col-xs-12 col-md-4">
</widget-list>

<widget-list title="Movies" class="col-xs-12 col-md-4">
</widget-list>

<widget-list title="Albums" class="col-xs-12 col-md-4">
</widget-list>

<script type="text/ng-template" id="template/widget/widget-list.html">
  <div class="widget widget-list">
    <div class="panel b-a">

      <div class="panel-heading b-b b-light">
        <h5>{{$widget.title}}</h5>
        <div class="pull-right">
          <button type="button" class="btn btn-default btn-sm" ng-click="$widget.doSomething()">
            Do something
          </button>
        </div>
      </div>

      <div class="panel-content">
        {{$widget.content || 'No content'}}
      </div>

    </div>
  </div>
</script>

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

Retrieve the CSS selector for the element that my plugin has been implemented on

Currently, I am in the process of developing a jQuery Plugin that is designed to be applied on a specific container element like so. $('#container').myPlugin(); Within this plugin, my goal is to retrieve the same element from another page using ...

The value of an AngularJS service is not being reflected in the view

I have implemented the stateProvider in my code, and I am facing an issue with updating the breadcrumbs in the header when the state changes. Instead of creating embedded views for each state, I have a service that shares an array of breadcrumbs containing ...

Component binding causing issues with onChanges functionality

There is a specific component that I am working on: @Component('Umbrella', { selector: 'attachment-list', templateUrl: '/AttachmentListComponent/AttachmentList.html', bindings: { mediaIds: '<' ...

Discover data using JavaScript recursively through paths

Here is the data structure I am working with: [ { name: 'root', children: [ { name: 'page', children: [ // and so on ] } ] } ] I am in need of a function that can retrieve ...

Unlocking Global Opportunities with Stencil for Internationalization

Hi there, I've been attempting to implement Internationalization in my stencil project but unfortunately, it's not working as expected. I'm not sure what's causing the issue, and all I'm seeing is a 404 error. I followed these arti ...

React variable should remain consistent and not change unnecessarily

I've been struggling with an issue for about 3 hours now, and I just can't seem to figure it out. Let me walk you through the problem with the code snippet below: import {useEffect} from 'react' function shuffle(tab) { console.table ...

Invoke v-on:click once new HTML has been added in Vue.js

Is it possible to trigger a function onclick after appending HTML in Vue.js using vue-append? this.html = '<div id="'+folderData[key].id+'" class="col-12 col-sm-6 col-md-4 col-lg-3 col-xl-2">' + ...

Replace the term "controlled" with "unleashed" when utilizing the file type input

In my app, I have defined multiple states like this: const [state,setstate]=React.useState({headerpic:'',Headerfontfamily:'',Subheaderfontfamilty:''}) And to get an image from my device, I am using the following input: &l ...

When Axios is disconnected, the sequence of events following a user's action is no longer dependent on when it is called after a button

I am working on a script that performs the following actions: Upon clicking a button, an encoded text is sent to an API for decoding. The decoded text is then used as a query for a Google search link that opens in a new tab. JAVASCRIPT // Summary: // ...

What are effective methods for testing HTML5 websites?

I'm currently working on a project to create a dynamic website using HTML5. The first page will prompt the user for specific inputs, and the following page will adjust accordingly based on these inputs. My main concern now is how to effectively test ...

Instructions for creating a distinct click listener for each <img> element inside a table cell

Within my table, each row contains multiple columns with images as data. I successfully implemented a 'common listener' that is triggered when any image within a table row is clicked. $('#mytable tbody td img').click(function () { // ...

"Unsuccessful Grails GSP Ajax Call: OnSuccess Function Fails to Trigger

Within my Grails .gsp file, I am executing an ajax call: $.ajax({ async: false, url: '<g:createLink controller="mycontroller" action="myaction"/>', data: params, dataType: 'json', contentType: 'application/json; ch ...

`A dynamically captivating banner featuring animated visuals created with JQuery`

I am currently in the process of designing a banner for the top of my webpage, but I have yet to come across any code that meets all my requirements. To provide clarification, I have attached an illustration showcasing what I am aiming to achieve. 1) The ...

Enhance the appearance of CodeMirror substrings by applying bold formatting without altering

I am currently utilizing codemirror with primefaces extensions in XML Mode. I need to modify the font style of a specific substring to make it bold. For instance, <User> <Name>Micheal</Name> <Age>25</Age> <Addr ...

What is the method for displaying x-axis dates below a highchart?

I'm encountering an issue with Highcharts where dates are not showing under the chart when passing series data as an array of objects. See result image The documentation mentions using an object instead of an array ([1649153340000, 45]docs I need t ...

What are some creative ways to design the selected tab?

In my Vue parent component, I have multiple child components. There are several elements that toggle between components by updating the current data. The issue is that I am unsure how to indicate which tab is currently active. I've tried various li ...

How can I input text into separate tabs using a specific method?

I've been struggling with this issue for a while now and here's the code I have so far: <html> <head> <script src="http://mihaifrentiu.com/wp-content/themes/mf/js/jquery_1.7.1.min.js" type="text/javascript"></scr ...

How can I customize the visibility toggles for the password input field in Angular Material?

Currently immersed in the Angular 15 migration process... Today, I encountered an issue with a password input that displays two eyes the first time something is entered in the field. The HTML code for this is as follows: <mat-form-field appearance=&qu ...

Angular UI-Router: Difficulty in Child State Accessing Parent Controller

I am currently using ui.router's nested views feature in my Angular application. Here is the relevant part of my .config: $urlRouterProvider.otherwise('/'); $stateProvider .state('home', { url: '/', templateUrl: ...

Access all areas with unlimited password possibilities on our sign-in page

I have set up a xamp-based web server and installed an attendance system. I have 10 users registered to log in individually and enter their attendance. However, the issue is that on the login page, any password entered is accepted without showing an error ...