modify the controller variable and incorporate it into the view using a directive in Angular 1.5

I need to update a controller variable from a child directive, but even after updating the controller variable, the value doesn't change in the view. Should I use $scope.$apply() or $digest?

Here is my code: http://plnkr.co/edit/zTKzofwjPfg9eXmgmi8s?p=preview

JavaScript file:

var app = angular.module('app', []);

app.controller('parentController', function($scope) {
    this.myVar = 'Hello from parent';

    this.refreshMyVar = function(data) {
        this.myVar = data.name;
        console.log('>> this.myVar', this.myVar);
    };
});

app.directive('myDirective', function() {
    return {
        restrict: 'E',
        replace: true,
        template: '<input type="file" />',
        bindToController: {
            attrFromParent: '='
        },
        controller: 'directiveController as directiveCtrl',
        link: function(scope, el, attr, ctrl) {
            el.bind('change', function(e) {
              ctrl.onChange(e.target.files[0]);
            });
        }
    };
});

app.controller('directiveController', function() {
    this.onChange = function(file) {
        this.attrFromParent(file);
    };
});

HTML file:

 <!DOCTYPE html>
<html lang="en-US">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
<script src="app.js"></script>
<body>

<div ng-app="app" ng-controller="parentController as parentCtrl">
  <h1> >> {{parentCtrl.myVar}}</h1>
  <p><my-directive attr-from-parent="parentCtrl.refreshMyVar" /></p>
</div>

</body>
</html> 

If you have any suggestions on how to improve my code, please share them.

UPDATE

app.controller('parentController', function($scope) {
    this.myVar = 'Hello from parent';

    this.refreshMyVar = data => {
        this.myVar = data.name;
        console.log('>> this.myVar', this);
        $scope.$parent.$apply(); // This resolved my issue
    };
});

$scope.$parent.$apply() solved my issue, but I'm open to other suggestions.

Answer №1

Initially, the syntax of your my-directive element is incorrect. It should not be a self-closing element as it is not valid HTML.

The correct syntax should be as follows

<my-directive attr-from-parent="parentCtrl.refreshMyVar"></my-directive>

Secondly, and importantly

app.controller('parentController', function($scope) {
    var vm = this;
    vm.myVar = 'Hello from parent';
    this.refreshMyVar = function(data) {
      // Avoid direct reference to "this" inside refreshMyVar function 
      // as "refreshMyVar" function runs in the context of the directive 
      // "this" will point to the scope of "myDirective" controller
      // console.log("this :" this); // try uncommenting to see what "this" refers to
      // By using "vm" you can access the actual "myVar" due to
      // the closure created by the refreshMyVar function at its inception.
      // console.log("vm :" vm); // try uncommenting to see what "vm" refers to
      // Understanding closures (a JavaScript concept) will be beneficial.
      vm.myVar = data.name;
      console.log(vm);
      alert('> this.myVar ' + vm.myVar);
      // Since refreshMyVar runs within the directive's context, you need to
      // call $apply on the parent scope to propagate the changes
      $scope.$parent.$apply();
    };
});

See the working plunker

Additionally, this article may provide further assistance.

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

Events triggered by JQueryUI's .selectable functionality

I am facing a minor issue with the JQuery .selectable function. My goal is to bind events to each tab. I have successfully handled the click event for each tab, but I'm struggling when it comes to selecting two or more tabs. For instance, if I clic ...

Updates to the visibility of sides on ThreeJS materials

When viewed from the back, the side is hidden as desired, but I am struggling to determine if it is visible from the renderer or camera. new THREE.MeshBasicMaterial({ map: new, THREE.TextureLoader().load('image.jpg'), side: THREE. ...

Tips for creating a dynamic menu item that stands out with a highlighted style

I would like to add a colored square to highlight the active menu item. .main-menu ul { padding: 0; margin: 0; text-align: center; } .main-menu li { list-style-type: none; display: inline-block; padding: 40px 0; } .main-menu a { font-fam ...

"How can I use node.js to retrieve the number of connections on an HTTP server

I have set up a Node.js HTTP server using the following code: http.createServer(function(req, res) {}).listen(8181); I am interested in finding a straightforward way to monitor the performance of my Node.js HTTP server from within the same process. I wou ...

Is it possible to create a mouse-following effect with lighting using Javascript

Recently, I've been honing my Javascript skills and decided to create a follow-mouse function. After successfully implementing it, I started brainstorming a new concept that I'm unsure is achievable. Is there a way to develop an "orb of vision" ...

Utilizing JavaScript to manage sections within a dropdown menu

When dealing with this particular HTML code, there is a feature where a list item includes options such as all, a, b, c, and d. If the user selects 'All', it should restrict them from choosing any other items. However, if they do not choose &apos ...

Enhance Vaadin 14: Automatically adjust TextArea size when window is resized

Using Vaadin 14.1.19 in a project called "My Starter Project," I attempted to create a TextArea that supports multiple lines. Initially, everything seemed fine, but upon resizing the TextArea, it failed to adjust the number of visible lines. Here is the co ...

Tips for maintaining consistent width of a div:

My current project involves designing a website that displays various quotes, with each quote rotating for a specific amount of time. However, I'm facing an issue where upon loading the page, the first quote triggers the appearance of a scrollbar, mak ...

How is it possible for the output to be a string array when the variable was declared as a number in TypeScript?

Snippet: function sampleFunction(sample:string|number|string[]) { if(typeof sample == "string") { console.log("Sample is String " + sample); } else if(typeof sample == "number") { console.log("Sample is Number " + sampl ...

Is it possible to use velocity js to add a gradient color effect to text content?

Can I use velocity js to apply gradient color to text? I've looked at https://css-tricks.com/snippets/css/gradient-text/ My specific need is to dynamically add a changing gradient using js. Thank you in advance. ...

Error: Express is undefined and does not have a property called 'use'

I'm encountering a problem with my express server specifically when I utilize the 'app.use' command. Within my task-routes.js file, the following code is present: import express from 'express'; const router = express.Router(); ...

Navigate to the initial visible element on the specified webpage via the page hash link

In my handlebars HTML template, I have a partial view that includes different pieces of content for desktop and mobile. I use different CSS classes to hide and show these elements accordingly. <div class='hideOnMobile showOnDesktop'> < ...

Validating JSON against a JSON schema using JavaScript

My current task involves validating approximately 100 JSON Objects against a specific JSON schema to ensure that all fields and their types align with the schema requirements. Initially, I attempted to use a JSON schema generated from a website. However, ...

The webkitTransitionEnd event fires prior to a repaint or reflow occurring

My goal is to create a progressBar that changes its width when an ajax request is made. I want the ajax callback to only execute after the animation of the progressBar is complete. Here is the code I am using: CSS: #progressBar{ position: fixed; ...

Using Vue.js to alter the CSS class property

I am exploring Vue.js and looking to modify a CSS class property. Here is the HTML code utilizing the specified class: <div class="customTimer"></div> Here is the corresponding CSS code: .customTimer { width: 100%; height: 1 ...

What is the process for altering the active status in pagination?

How can I make the active class in my pagination appear in red? Here's the code snippet I have: In my script.js file: $(".pagination").append("<li class='page-item' id='previous-page'><a class='page-li ...

Unlocking the potential of Arrays in Javascript: strategies for extracting maximum value

After running a database query in node, I received the result in the form of an object: [ [1234] ]. Now, I am trying to extract this value and convert it into a string so that I can pass it onto the client side. Although I have written the necessary code ...

How come despite installing node 10.1.0, the system is showing the installed version as 5.6.0?

After I downloaded the NPM Windows installer from this link: https://nodejs.org/it/, I made sure to download and install the 10.1.0 version. However, when I checked my console using the command node -v, I was surprised by the following output: C:\U ...

The ui-sref function is producing an incorrect URL

I am currently developing a project using Angularjs with Nodejs. For routing purposes, I have incorporated UI-router into my project. Below are the state configurations within my app module file: app.config(function ($stateProvider, $urlRouterProvider) { ...

What is the most efficient way to post an array and iterate through it using PHP?

As the user types into an input field, jQuery's replace function is used to immediately create an array. The objective is to send these values to PHP for a live search on a specific MySQL table. I've managed the input field and the ajax call, bu ...