Bidirectional data flow connecting controller with external directive

My system:

Picture a manager for an online shopping cart:

app.controller('CartCtrl', function ($scope) {
    $scope.data = [
        {
            id:0,
            title:'product1'
        },
        {
            id:1,
            title:'product2'
        }
    ];

    $scope.countItems = function(){
        var total = 0;
        for(var i in $scope.data){
            total++
        }
        return total;
    } 
});

This functionality is placed on a specific part of the page:

<ul ng-controller="CartCtrl">
    <li ng-repeat="item in data">{{item.title}}</li>
</ul>

Elsewhere, I wish to show the number of items in my cart:

<div cart-item-number>{{countItems()}}</div>

To link the information I utilize a command:

app.directive('cartItemNumber', function() {
    return {
        restrict: 'A',
        controller: 'CartCtrl'
    };
});

My Query:

When the page loads, it displays the correct number. However, if an item is added or removed from the data object, the cart-item-number does not refresh.

What steps can I take to address this problem?

Answer №1

There is a distinction between ng-controller="CartCtrl" and controller: 'CartCtrl'. The former is specified in the directive declaration for the directive, while the latter initializes with the same data when your application starts, leading to consistent functionality.

If you simply want to display the number of items within the scope of CartCtrl, there's no need for a directive (consider using data.length instead). However, if you aim to display it outside of that scope, communication needs to be established. Alternatively, moving your cart higher up in the hierarchy of scopes, such as on the $rootScope, would make it visible throughout your application (unless an isolated scope is in use).

Answer №2

To begin with, the issue at hand arises due to working on different scopes. Let's take a look at this example:

<body>
  <ul ng-controller="CartCtrl">
    <li ng-repeat="item in data">{{item.title}}</li>
  </ul>
  <div cart-item-number>{{countItems()}}</div>
</body>

In this scenario, the directive registers on RootScope, while ngController operates on a child scope. Consequently, you end up with duplicated data. I recommend using the AngularJS Batarang Chrome plugin to visualize the scopes and models mentioned above.

If you move the ng-controller in the example above to the body, you will observe the expected behavior.

Nevertheless, employing controllers in this manner is frowned upon. A directive controller should primarily serve as a means of exposing an API to other directives for direct communication. On the other hand, "normal" controllers (utilized in ngController and routes) are employed to enhance scope and incorporate functionality into the scope object.

If there is a need for communication between a "normal" controller and a directive, it is advisable to either utilize a mediator service (where both the controller and directive depend on this service) or employ $scope events like $scope.$broadcast and $scope.$emit for communication. This approach decouples controllers from directives, facilitating the creation of reusable components and simplifying testing processes.

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

Can you please tell me the event that is triggered when an option is unselected in Vue.Drag

I am trying to figure out the event for selecting an item since I already know about the "choose" event. However, I am uncertain about what to use for un-selecting an item. In my particular case, I am unable to utilize the @end event. <draggable :list= ...

Creating a interactive navigation bar with External JSON data in HTML and JavaScript

Is there a way to create a dynamic MenuBar by using an external JSON file? How can I write HTML code to fetch and display JSON data dynamically? What is the process for reading a JSON file? //JSON File = Menu.Json {"data": [{"id": "1", "text": "F ...

Encountered an Error with My Protractor Script - Object Expected

Currently, I am in the process of learning automation testing for an AngularJS application. However, I have encountered an "object expected" error on line 4, which is pointing to the first line of my script. describe("Homepage", function() { it("Navig ...

"Error: The req.body object in Express.js is not defined

edit:hey everyone, I'm completely new to this. Here's the html form that I used. Should I add anything else to this question? <form action="/pesquisar" method="post"> <input type="text" id="cO" ...

Guidance on exporting an Excel file from an HTML table, excluding the final row, using JavaScript

I'm able to export an Excel file from an HTML table, but I'm facing an issue where the last row (tr) meant for pagination on the screen is also being included in the exported result. How can I exclude this row from showing up in the Excel file? ...

Encountering a Zone.js error when trying to load an Angular 7 app using ng serve, preventing the application from loading

Scenario: Yesterday, I decided to upgrade my Angular app from version 5.2.9 to 6 and thought it would be a good idea to go all the way to 7 while I was at it. It ended up taking the whole day and required numerous changes to multiple files, mostly due to R ...

Choose a specific element using jQuery based on a class that is shared by several elements

I am looking to target an element with the class 'submenu-expand' and apply an additional class to it. $('.menu-item').on('click',function(){ $('.submenu-expand').toggleClass('expanded') }) While this cod ...

The second parameter of the Ajax request is not defined

Having an issue with my Ajax request in Vue.js where the second parameter is logging as undefined in the console. I've been trying to fix this problem but haven't found a solution yet. This is the code snippet for $.ajax(): //$.ajax() to add ag ...

"jQuery's .each() method is only iterating through the last element in

I am encountering an issue with this function not operating correctly... only the last Element shows the box. NOTES: <aside> is set to position: fixed; and I understand that this is not the "correct" use of <article> tags, but it helps me dist ...

The process of including or excluding an item in an array

There are 2 toggle buttons. If the value is true, it will be added to the array, otherwise the element will be removed. data: originality: [] toggles: <toggle id='1' ref='toggleOriginal'> Click </toggle> <toggle id=&apo ...

Choosing items in an MVC view using KnockoutJS

I am currently working on implementing a generic ASP.net MVC view that displays a list of available and selected items loaded from the server. Users have the ability to make changes to the list by selecting new items from the available list and removing it ...

Adding a character at the current cursor position in VUE JS

My quest for inserting emojis in a textarea at the exact cursor position has led me to an extensive search on Vue JS techniques. However, most resources available online provide solutions using plain Javascript. Here is the code snippet I am working with: ...

Display a collection of pictures from a directory on a website using JavaScript

I am having trouble displaying a collection of images from a specific folder using JavaScript/jQuery. Below is the code snippet I am working with: $(document).ready(function(){ var dir = "images/"; // specified folder location var fileextension ...

Displaying an image within a textarea using JS and CSS

Could someone help me create a form with textareas that have small images on them? I want clicking on the image to call a function fx(). Can anyone code this for me using JavaScript/jQuery/CSS? In the image below, clicking on "GO" will call Fx() I attemp ...

Tips on retrieving values from input files using jQuery

Is there a way to retrieve the value of an input type using jQuery? Specifically, when I add a file to the input file, I want to dynamically add more input types with the file's value. Currently, I am using the following code: $('#show_input&apo ...

I am looking to transform CSV data into XLSX file format, upload it to AWS, and obtain the corresponding URL

I am currently in the process of converting a JSON file to CSV. My next step is to convert this CSV file to XLSX data and upload it to AWS to retrieve the link. Convert CSV to XLSX const xlsxFilePath = 'path/to/transaction_data.xlsx'; await csvto ...

Fade In/Out Scroll Effect

As the user scrolls down the page, I have a slider that smoothly slides from right to left. What I'm trying to achieve is for the slider to fade out when the last slide is no longer in view during downward scrolling, and fade back in as the last slid ...

Utilizing JS datepicker for multiple input fields sharing a common class

After trying to implement the js-datepicker plugin from https://www.npmjs.com/package/js-datepicker, I ran into an issue. I have multiple input fields in which I want to use the same date picker, so I assigned them all the class 'year'. Unfortuna ...

Sorting items in backbone.js can be achieved by using the sortBy method

Currently, I am delving into learning backbone.js and have decided to create my own Todo application using backbone.js along with a local storage plugin. At this point, I have successfully developed the Todo app where you can add and remove tasks. However, ...

A guide on creating a Utility function that retrieves all elements in an array starting from the third element

I've been working on a tool to extract elements from an array starting after the first 2 elements. Although I attempted it this way, I keep getting undefined as the result. // ARRAYS var arr = ['one', 'two', 'three', &a ...