How to Remove a Dynamically Generated Popover in Angular

As a newcomer to angular, I successfully implemented a bootstrap popover around selected text using the following function:

 $scope.highlight = function () {

        var a = document.createElement("a");
        a.setAttribute('tabindex', "0");
        a.setAttribute('data-toggle','popover');
        a.setAttribute("id","1");
        a.setAttribute('data-content',"<button type='button' class='btn btn-default' ng-click='deleteLabel()'><small><span class='glyphicon glyphicon-remove'></span></small></button>");
        a.setAttribute('data-html','True');

        if (window.getSelection) {
                var sel = window.getSelection()
                var range = sel.getRangeAt(0).cloneRange();
                range.surroundContents(a);
                sel.removeAllRanges();
                sel.addRange(range);
        }

        $timeout(function(){
          $('[data-toggle="popover"]').popover();
        }, 50);
    };

Within the above code, the popover includes a button that should trigger the deleteLabel() function upon click. This function is supposed to remove the element:

 $scope.deleteLabel= function(){
            alert("removing label");
            var labelEl=document.getElementById("1");
            labelEl.remove();
        };

However, it seems like deleteLabel() is not being executed when the button in the popover is clicked. Is there an issue with how I'm calling this function from within the popover?

Answer №1

Here is a more Angular approach using ngBootbox; you can check out the live example on Plunker. In essence, it's recommended to steer clear of directly manipulating the DOM as done in jQuery. Angular excels at abstracting this complexity through features like directives such as ngBootbox. If there's a jQuery plugin you wish to integrate, look for an equivalent Angular wrapper.

If I've grasped your needs accurately, there are two pop-ups implemented: one for adding elements and another for confirming element deletions.

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

app.controller('MainCtrl', ['$scope', '$ngBootbox', function($scope, $ngBootbox) {
  var vm = this;

  vm.name = 'World';
  vm.categories = ['Category 1', 'Category 2'];

  vm.prompt = function() {

    $ngBootbox.prompt('Enter a new category?')
      .then(function(result) {
        console.log('Prompt response: ' + result);
        vm.categories.push(result);
      }, function() {
        console.log('Prompt dismissed!');
      });

  }

  vm.delete = function(index) {
    console.log('delete index=' + index + ' value=' + vm.categories[index]);
    $ngBootbox.confirm('Are you sure you want to delete ' + vm.categories[index] + ' ?')
      .then(function(result) {
        // Remove element
        vm.categories.splice(index, 1);
      }, function() {
        // Do nothing
        console.log('Prompt dismissed!');
      });
  }
}]);

When adding, I trigger a prompt where users can input a category that gets added to the array upon confirmation, automatically updating the page.

For deletion, I utilize the $index from ng-repeat to determine which element to remove. Upon user confirmation, the selected item is removed from the array using splice, with Angular taking care of the UI update.

and the HTML:

<body ng-controller="MainCtrl as vm">
  <p>Hello {{vm.name}} !</p>
  <ul>
    <li ng-repeat="c in vm.categories">{{c}} <a href="" ng-click="vm.delete($index)">Delete</a></li>
  </ul>
  <a href="" ng-click="vm.prompt()">Add Category</a> 
</body>

ngBootbox: AngularJS wrapper for Bootbox.js, which simplifies implementing Twitter Bootstrap modals for alerts, confirms, and prompts. ngBootbox consists of three directives, each corresponding to alert, confirm, and prompt functionalities.

Bootbox.js: A concise JavaScript library enabling creation of dialog boxes utilizing Bootstrap modals programmatically, without fuss over managing required DOM elements or JS events. Here’s a basic example:

Considering your beginner status in Angular, I adopted the controller as syntax and vm=this pattern to circumvent potential $scope complications; here's an informative read: AngularJS's Controller As and the vm Variable

Answer №2

There's a better approach to handling this task. Consider utilizing AngularJS directives for DOM manipulation or incorporating libraries such as Bootstrap UI.

The issue with your current implementation lies in the fact that the DOM element created using createElement is not properly bound.

Answer №3

Check out this live plunker example showcasing the popover feature. Users can select text, click on highlight, and a link is generated using the provided code which triggers the delete function upon clicking the delete button. To ensure ng-click functionality, I compile the element with:

$compile(a)($scope);

The content is displayed within a div marked 'mycontent' for identification to delete selected text:

<body ng-controller="MainCtrl as vm">
  <p id='mycontent'>{{ vm.content }}</p>
  <button ng-click="vm.highlight()">Highlight</button>


  <script type="text/ng-template" id="tpl.html">
    <div class="popover-content">
      <div>
        <div>
          <span>{{link.title}}</span>
        </div>
        <div>
          <button ng-click='vm.delete()'>Delete</button>
        </div>
      </div>
    </div>
  </script>
</body>

This application is built based on your code structure:

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

app.controller('MainCtrl', function($scope, $compile, $timeout) {
  var vm = this;
  vm.window = window;

  vm.content = 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum';

  vm.delete = function() {
    console.log('delete' + vm.selectedText);
    var d = document.getElementById('mycontent');

    var olddiv = document.getElementById('todelete');

    d.removeChild(olddiv);
  };

  vm.highlight = function() {

    var a = document.createElement("a");

    a.setAttribute('id', 'todelete');
    a.setAttribute('uib-popover', '');
    a.setAttribute('popover-trigger', 'click');
    a.setAttribute('popover-placement', 'top');
    a.setAttribute('ng-click', "info()");
    a.setAttribute('data-html', 'True');
    a.setAttribute('data-content', 'Some content');
    a.setAttribute('uib-popover-template', "'tpl.html'");


    $compile(a)($scope);

    if (window.getSelection) {
      var sel = window.getSelection()
      var text = "";
      if (window.getSelection) {
        text = window.getSelection().toString();
      } else if (document.selection && document.selection.type != "Control") {
        text = document.selection.createRange().text;
      }
      vm.selectedText = text;
      var range = sel.getRangeAt(0).cloneRange();
      range.surroundContents(a);
      sel.removeAllRanges();
      sel.addRange(range);
    }

  };

  vm.getSelectionText = function() {
    var text = "";
    if (window.getSelection) {
      text = window.getSelection().toString();
    } else if (document.selection && document.selection.type != "Control") {
      text = document.selection.createRange().text;
    }
    return text;
  };

});

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

Eliminate items from a list that have duplicate properties

I have a collection of objects, each with a unique NAME property. However, there are duplicates in the collection where some objects share the same NAME. const arr = [ {name: "x", place: "a", age: "13" }, {name: "x", place: "b", age: "14" }, { ...

Utilizing React Native for seamless deep linking with automatic fallback to a webpage, including the ability to pass

I am currently working on a project that involves a website built with React and a React-native app for camera functionality and data processing. On the website, there is a button that opens the camera in the React-native app through deep-linking. This pa ...

Tips for sharing a global variable across numerous functions in various files

<script> var words = new Array(); words[1] = 'fresh'; words[2] = 'ancient'; </script> <script src="scripts/validation.js" type="text/javascript"></script> Additionally, in the validation.js file, we find: fu ...

I'd like to change the name of the JSON key retrieved from the API request

I have a JSON format stored in my database that looks like this. [ { ip.src:"192.168.200.10", y:1506 }, { ip.src:"192.168.200.10", y:1506 }, { ip.src:"192.168.200.10", y:1506 }, { ip ...

Verify in Jquery whether a table row contains no elements with a specified class before removing any duplicates

I have an HTML table: <div class="1233">hello</div> <table cellpadding="0" cellspasing="0" class="sortable zebra tablesorter tablesorter-default" id="articles-table"> <thead> <tr class="tablesorter-headerRow"> ...

AngularJS $http.post() response function not executing in the correct sequence

When calling a function from my angular controller to make a $http.post() request, the code below the function call is executing before the successFunction(), preventing the code inside the if block from running. How can I ensure the if block executes wi ...

Is it possible to utilize TypeScript code to dynamically update the JSON filter with variable values?

I am dealing with a JSON filter in which the value for firmwareversion needs to be replaced with a dynamic value. Here's how I've set it up: //JSON filter this.comX200FilterValue = '{ "deviceType": "ComX", "firmwareV ...

Struggling to get Canvas2ImagePlugin to function properly within an Ionic app and Angular.js

Recently, I stumbled upon a plugin that allows me to save images in my App, a solution I have been struggling to find. My question is: how do I integrate this into an angular framework? As a newcomer to angular.js, I'm feeling quite lost. The code sni ...

Building New Web Pages with Express in Node.JS

I want to dynamically generate a new page on Node.JS with Express upon user form submission. Here is my initial approach, but it's not working as expected: var app = require('express')(); var server= require('http').createServer(a ...

Does anyone else have trouble with the Smtp settings and connection on Servage.net? It's driving me crazy, I can't figure it out!

Whenever I attempt to connect to send a servage SMTP, it gives me this error message: SMTP connect() failed. I have tried using the following settings: include('res/mailer/class.phpmailer.php'); $mail->SMTPDebug = 2; include('res/mai ...

Retrieve a form (for verification purposes) from a separate AngularJS component

I'm facing an issue with accessing a form from one component to another in my project. One component contains a form, and the other has navigation buttons that, when clicked, should validate the form before moving on to the next step. However, I alway ...

Combining data from an object within an array in JavaScript

I am looking for a way to incorporate values from an Object (weekdayMap) into an existing array (vehicleAvailabilities) that contains objects. I require the value Montag on day one and Dienstag on day two. This pattern continues for each day of the week. ...

Identifying a Malformed URI in JavaScript

In JavaScript, it is considered a best practice to use certain patterns to detect errors instead of solely relying on try-catch blocks. One easy way to do this is by using TypeError: if (typeof foo !== "number") { console.log("That ain't a number!" ...

What is the best way to determine the file size using Node.js?

My current challenge involves using multer for uploading images and documents with a restriction on file size, specifically limiting uploads to files under 2MB. I have attempted to find the size of the file or document using the code below, but it is not p ...

A technique, such as regular expressions, can be used to detect the quantity of newline characters in the text entered by the user in a text area

I'm trying to figure out how to count the number of newline characters (or whatever is inserted when the user presses the return key) in a textarea's value. I believe I should be using a regular expression for this task, but I'm not very ski ...

Converting data to JSON geometry format for implementation in Three.js

Currently, I am in the process of creating an exporter using Maxscript to convert data into JSON format for use in Three.js. Information on this topic is scarce, but I did come across a helpful resource: https://github.com/mrdoob/three.js/wiki/JSON-Geometr ...

Retrieve information from a variety of selected checkboxes

Is there a way to retrieve the values of check boxes that are generated dynamically? @ $db = mysql_connect("abc", "abc", ""); mysql_select_db("abc"); $strSQL = "SELECT * FROM student"; ...

Is there a way for me to modify the formatting of the text that I

Can you help me transform a text that looks like this: '?category=1,2&brand=1' into something like this: '?categories[]=1&categories[]=2&brands[]=1'? I'm not quite sure how to make this change. ...

Access previous value in Vuejs onchange event

In the code snippet below, how can I retrieve the previous value of the model that has been changed, specifically the age in vuejs? var app = new Vue({ el:"#table1", data:{ items:[{name:'long name One',age:21},{name:'long name Two&a ...

Having trouble with React's conditional rendering not working as expected?

I am currently working on updating the contents of my Navbar and Router by using useContext and conditional rendering techniques. Here is a snippet from my App.js: import "./App.css"; import axios from "axios"; import { AuthContextProv ...