No longer able to bind events after making changes to SVG elements [using JSFiddle]

I've coded a personalized directive to display tags like `<rect>` and `<circle>` within `<svg>` elements.

My shapes model is simply an array of objects with different attributes such as `width`, `height`, and `stroke-width.

These shapes are then visualized in an SVG element by my custom directive.

<svg height="400" width="600">
  <dr-shape ng-repeat="shape in shapes"></dr-shape>
</svg>

The definition of the directive includes detailed comments:

app.directive('drShape', ['$compile', function($compile) {
  // A function to add attributes to an element.
  var bindNgAttr = function(el, attribute, value) {
    el.attr('ng-attr-' + attribute, '{{shape.' + attribute + '}}');
  };

  return {
    restrict: 'E',
    link: function(scope, element, attrs) {

      // Function that creates a DOM node using `document.createElementNS`
      // for appending it to an SVG element along with its attributes.
      var shape = makeNode(scope.shape.tagName, element, attrs);
      var elementShape = angular.element(shape);

      // This section assigns the shape's attributes to the created node. 
      for (var attribute in scope.shape) {
        if (isPublic(attribute, scope.shape[attribute])) {
          bindNgAttr(elementShape, attribute);
        }
      }

      // Add click listener to change fill color when clicking on a shape.
      elementShape.on('click', function() {
        console.log('Clicked in directive');
        scope.shape.fill = '#bada55';
      });

      element.replaceWith(shape);

      // Not sure what this does. Source: http://goo.gl/ZoYpQv
      attrs.$observe('value', function(value) {
        scope['value'] = parseInt(value, 10);
        $compile(shape)(scope);
      });
    }
  };
}]);

Rendering some shape data results in the following SVG output:

<svg height="400" width="600">
  <!-- ngRepeat: shape in shapes -->
  <rect ngRepeat="shape in shapes" strokeWidth="3" ng-attr-stroke="{{shape.stroke}}" ng-attr-fill="{{shape.fill}}" ng-attr-x="{{shape.x}}" ng-attr-y="{{shape.y}}" ng-attr-width="{{shape.width}}" ng-attr-height="{{shape.height}}" ng-attr-tagname="{{shape.tagName}}" stroke="#aea086" fill="#fff" x="239" y="89" width="25" height="22" tagname="rect"></rect>
  <!-- end ngRepeat: shape in shapes -->
  <rect ngRepeat="shape in shapes" strokeWidth="3" ng-attr-stroke="{{shape.stroke}}" ng-attr-fill="{{shape.fill}}" ng-attr-x="{{shape.x}}" ng-attr-y="{{shape.y}}" ng-attr-width="{{shape.width}}" ng-attr-height="{{shape.height}}" ng-attr-tagname="{{shape.tagName}}" stroke="#a265e7" fill="#fff" x="233" y="6" width="12" height="43" tagname="rect"></rect>
  <!-- end ngRepeat: shape in shapes -->
</svg>

Check out this JSFiddle with the provided code.

Despite trying scope.$apply() and scope.$digest() in the click handler, I couldn't update the corresponding SVG DOM node upon manipulating the data in the shapes model. (EDIT: This statement is incorrect — refer to my response below.)

How can I ensure that changes made to the data reflect in the view?

Answer №1

After some trial and error, I discovered that invoking scope.$apply() does indeed function properly within the click handler. It's unclear what led me to believe otherwise.

  elementShape.on('click', function() {
    console.log('Clicked in directive');
    scope.shape.fill = '#bada55';
    scope.$apply();
  });

Furthermore, there was an oversight in my JSFiddle that exacerbated the issue. Check out the corrected version in this updated fiddle.

I apologize if this caused any unnecessary confusion!

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

A guide to implementing angularjs app.service and $q in typescript

I am fairly new to TypeScript and AngularJS and I am struggling to find the correct answer for my issue. Below is the relevant code snippet: export class SidenavController { static $inject = ['$scope', '$mdSidenav']; constructor(p ...

Adjusting the empty image source in Vue.js that was generated dynamically

Currently experimenting with Vue.js and integrating a 3rd party API. Successfully fetched the JSON data and displayed it on my html, but encountering issues with missing images. As some images are absent from the JSON file, I've saved them locally on ...

`I'm experiencing difficulty sending JSON data to Typeahead using PHP`

I am having trouble passing an array of data from PHP to typeahead. I have tried various solutions but nothing seems to work. When I display the response on the console, it shows the array of strings but they are not populating in the typeahead field. PHP ...

Are you curious about the array of elements in React's carousel?

I'm currently in the process of constructing a website using React, and I have a specific challenge related to the "news" section. Within this section, I have a list of three components that represent different news items. These components are housed ...

The bootstrap navbar dropdown feature isn't functioning properly on iPhones

Currently utilizing "bootstrap": "~3.3.4" within the mean.js framework, I am facing an issue with the navbar dropdown menu. On desktop, everything functions as expected - the dropdown opens and remains open when the icon is clicked. However, once deployed ...

Troubleshooting: Issue with onclick event in vue.js/bootstrap - encountering error message "Variable updateDocument not found"

As a newcomer to frontend development, I have a basic understanding of HTML5, CSS, and Javascript. Recently, I started working on a vue.js project where I integrated bootstrap and axios. Everything seemed to be working fine until I encountered an issue whe ...

Dealing with errors when implementing an Angular 2 route guard that returns an Observable of type boolean can be a

My route guard is implemented as follows: @Injectable() export class AuthGuard implements CanActivate { constructor(private router: Router, private authenticationSvc: AuthenticationService) { } canActivate(): Observable<boolean> { return this. ...

What is the best way to validate user input in a CRUD application built with the MEAN stack?

Currently, I am developing a CRUD application and the snapshot above showcases its design. I have successfully implemented validation for updating in this application after referring to a guide on Stack Overflow. Despite my efforts, I have been unable to ...

Vue: restrict entry to the view unless props are configured

Currently, I am in the process of creating a Vue game that consists of two main views: a 'setup' view and a 'play' view. The values that are configured in the setup view are then passed as props to the play view, initiating the game wit ...

I am experiencing issues with my three.js script not functioning properly within the context of a

I have been working on implementing a raycaster function in my project that only activates when an entity is visible. To achieve this, I was advised to create a custom script for better control. I have set up all entities and their child entities to be in ...

Apply a custom filter to ng-repeat results

Asking for advice on how to iterate over an array using ng-repeat and filter the contained objects based on a function property. Find more details in this Plunker link. Let's say we have an object like this: vm.show1 = function(){ return true; }; ...

Exploring AngularJS: Maximizing multi-module functionality and enhancing communication between modules

Currently, I am on the lookout for well-structured tutorials or resources that delve into AngularJS and multi-modules. It seems like a smart move to divide Angular into modules rather than relying on just one module as seen in most of the existing tutorial ...

Can an inline try be implemented without including a catch block as demonstrated?

I have a scenario where I need to execute code that may result in an error without catching it. If the response is not valid JSON, then the desired outcome should be 0: Here is the code snippet I am considering: var overallProgress = try {JSON.parse(text ...

Discover each *distinct arrangement* from a given array

I'm looking to generate unique combinations of element positions in a JavaScript array. Here's the array I am working with: var places = ['x', 'y', 'z']; The combinations I want are: [0,1], [0,2], [1,2]. Current ...

Creating a new Express JS application

I've encountered an issue with my express application. When I run the server and navigate to localhost in my browser, the index page loads but without the image that should be displayed. The browser console shows a 404 error for the image URL. GET ht ...

Toggle the visibility of a component in React by managing its state

Currently, I am faced with the challenge of toggling the visibility of a component based on a state value: import React, { Component } from 'react'; import logo from './logo.svg'; import './App.css'; import Button from ' ...

Extract Information from a Website

Is there a way to extract data from another website using JavaScript and save it into a .TXT or possibly an XML file? If JavaScript is not the best solution, I am open to other suggestions. I am specifically interested in extracting the price and item na ...

Footer placement not aligning at the bottom using Bootstrap

I'm having trouble getting my footer to stay at the bottom of my website without it sticking when I scroll. I want it to only appear at the bottom as you scroll down the webpage. Currently, the footer is positioned beneath the content on the webpage. ...

what is the process of optimizing HTML using the grunt htmlmin plugin?

After creating an Angular app with Yeoman, I attempted to minify my HTML files using Grunt and htmlmin. The configuration for htmlmin is as follows: htmlmin: { dist: { options: { collapseWhitespace: true, ...

What is the most effective method for fetching images from MongoDB?

I'm currently working on a web application that uses MongoDB's GridFS to store and retrieve images. However, I'm facing an issue where retrieving images from the database takes significantly longer than expected when a user makes a request. ...