Using Bootstrap4 tagsinput, removing a tag: detecting for AJAX fulfillment and then reversing the action

Utilizing tagsinput in conjunction with bootstrap4, my goal is for the user to be able to delete a tag by clicking on the 'x' button. Upon deletion, an ajax request is sent to the server to verify if the user has permission. The server will respond with either yes or no (and proceed to delete the tag from the database if allowed). Subsequently, tagsinput should be notified to remove the tag from both the input element and its internal state on the client side.

To achieve this, I have incorporated the beforeItemRemove event into the tagsinput-element and utilized event.cancel=true; to prevent tag deletion. Here's how:

$(inputel).on('beforeItemRemove', function(event) {
  ajaxreq(..., onSuccess(r){}, onError(e,m){ event.cancel = true; });
});

Unfortunately, setting event.cancel comes too late as the event wraps up before the completion of the ajax request!

Hence, what I ultimately resorted to was:

event.cancel = true; // cancellation of deletion by default
$(inputel).on('beforeItemRemove', function(event) {
  ajaxreq(..., onSuccess(r){
   // If ajax succeeds and the server permits deletion, we also remove it from inputel
   $(inputel).tagsinput('remove', event.item, {preventPost: true});
}, onError(e,m){});
});
// The event fires much earlier than the ajax request completes,
// but with event.cancel=true, it remains inactive until triggered by 'remove'

Is this solution correct?

UPDATE: For further reference, please visit: (search for beforeItemRemove)

ANOTHER UPDATE: After testing, I can confirm that this method works when a user is denied permission to delete a tag, preventing any changes within the input field. However, in scenarios where deletion is permitted and executed, the event triggers repeatedly (despite preventPost: true, which presumably removes without triggering the removal event) and causes issues in the database.

Answer №1

My solution involved cloning and patching the JS file bootstrap-tagsinput.js from a source that I found as my last resort, which surprisingly worked. However, this method is far from ideal since there are numerous other bootstrap "tagsinput" JS files available, making it a rather poor choice.

The changes were made in three specific areas:

1) The registration of the functions add and remove. It was essential to modify them so that they could accept a 3rd parameter, even though their signature implied they already accepted 3 parameters (with the last one being an object with keys like preventPost). Surprisingly, the registration below did not pass the 3rd argument properly:

 /* bliako modifies: add arg4 at the end, after arg3: */
$.fn.tagsinput = function(arg1, arg2, arg3, arg4) {
   var results = [];
   
   this.each(function() {
...
      } else if(tagsinput[arg1] !== undefined) {
          // Invoke function on existing tags input
/* bliako modifies: */
var retVal = tagsinput[arg1](arg2, arg3, arg4);
/* bliako modifies: comment out the following - which may introduce side-effects, as the issue lies in how these functions receive the options 3rd argument without arg4 (arg1 being the function name, e.g."add") 
This will hopefully ensure that options={preventPost: true} is passed back to the add() and remove() functions.
*/
/*            if(tagsinput[arg1].length === 3 && arg3 !== undefined){
               var retVal = tagsinput[arg1](arg2, null, arg3);
            } else{
               var retVal = tagsinput[arg1](arg2);
            }
*/

2) A modification in the "add" function to prevent triggering events when the options argument contains preventPost: true.

// Do not trigger the event if preventPost == true
if( (options == null) || ! options.hasOwnProperty('preventPost') || ! options.preventPost ){
      var beforeItemAddEvent = $.Event('beforeItemAdd', { item: item, cancel: false, options: options});
      self.$element.trigger(beforeItemAddEvent);
      if (beforeItemAddEvent.cancel)
         return;
} else { console.log("tags/remove() : blocked beforeItemRemoveEvent"); }

3) Similar modifications were applied to the "remove" function:

// Do not trigger the event if preventPost == true
if( (options==null) || ! options.hasOwnProperty('preventPost') || ! options.preventPost ){
        var beforeItemRemoveEvent = $.Event('beforeItemRemove', { item: item, cancel: false, options: options});
        self.$element.trigger(beforeItemRemoveEvent);
        if (beforeItemRemoveEvent.cancel)
          return;
} else { console.log("tags/remove() : blocked beforeItemRemoveEvent"); }

The main concept behind these modifications is to enhance the functionality by allowing the add and remove functions to recognize a 3rd parameter as options, enabling users to pass options such as add(item, dontpushval, {preventPost: true}). Furthermore, these functions were adjusted to read the options parameter effectively whenever the preventPost property exists and is set to true, preventing the triggering of certain events.

This situation highlights the flaws in the web system and how many successful businesses are built upon unstable foundations.

Best regards, bliako

p.s. It's surprising that no trolls from certain platforms have labeled this question irrelevant or off-topic yet. Perhaps they are preoccupied with some sort of community meeting to make their platform "greater".

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

The JavaScript function I created to remove the last item in an array is not functioning correctly when it encounters an "else

My button has been designed to delete the last index from this.fullformula, which is a string. However, I've encountered an issue with deleting characters from this.result, which is an integer. Instead of looping over the function, it only deletes one ...

The functions Show() and Hide() may not work in all scenarios within jQuery

I'm currently developing a website that allows users to participate in quizzes. Each quiz consists of 20 questions divided into three sections: 1 mark for 10 questions, 2 marks for 5 questions, and 4 marks for 5 questions. For each question, there are ...

What separates name="" from :name=""?

If the :name="name" syntax is used, the value of the name attribute will be the unique data it receives from the props. However, if I use name="name" without the preceding :, then it will simply be "name". What role does the : play in the name attribute? ...

Creating an Array in AngularJS with ng-model and submitting it with jQuery: A comprehensive guide

I am struggling to submit an array of values using jQuery and AngularJS. Whenever I click the submit button, only the first array value is being retrieved. How can I get all array values using ng-model? Here is a link to all my code: https://jsfiddle.net/r ...

Is the fulfillment of AngularJS $q promises determined by the return value?

I'm currently working with angularjs 1.6.1 and $q. My task involves fetching a large amount of data from an API. I'm struggling to grasp when promises are actually fulfilled. Here's a snippet of what I'm doing: // controller this.dataO ...

JavaScript: Techniques for extracting multiple digits from a text

Enter: "WASHINGTON (Reuters) U.S. stock index futures indicated a marginal recovery on Wall Street on Thursday, as futures for the S&P 500 rose by 0.34 percent, Dow Jones futures gained 0.12 percent, and Nasdaq 100 futures increased by 0.51 percent ...

Hiding labels using JQuery cannot be concealed

Why isn't this working? -_- The alert is showing, but nothing else happens. <asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeaderContent"> <script type="text/javascript"> if (navigator.userA ...

Adjusting Google Maps API v3 Autocomplete dropdown width with JavaScript and SASS to match input field dimensions

I am facing an issue where the autocomplete dropdown (div with class "pac-container") is consistently 4 pixels shy of aligning perfectly with the right side of the input field. It looks like this: https://i.sstatic.net/Y0oq1.png Below is the HTML code: ...

What is the best way to call an API and display the retrieved value in a div upon the page loading?

Seeking help to retrieve data from an API and display the response within a div tag. I know it's possible with jQuery, but I prefer a different approach. Currently, the page is loading blank. <body> <div id="OnLoad"></div& ...

Issue with Angular Swiper carousel: Error message pointing to node_modules/swiper/angular/angular/src/swiper-events.d.ts

I am attempting to implement a carousel in Angular using Swiper (). An error message is appearing: Error: node_modules/swiper/angular/angular/src/swiper-events.d.ts:3:50 - error TS2344: Type 'SwiperEvents[Property]' does not meet the constraint ...

Encountering an Assertion Error when attempting to import a custom package in Angular 13

Seeking assistance: I have developed my initial Angular package which offers various services for making HTTP requests to a server and fetching results. Upon importing the service, the webpage ceases to render and displays the following error message: cor ...

Accessing the Bootstrap tab form from an external source

I currently have Bootstrap tabs on a page and they are functioning correctly. However, I am looking to open these tabs from an external page. Is this feasible? <div role="tabpanel"> <ul class="nav nav-tabs" role="tablist"> ...

Transferring Data in Vue.js Components through Props

I've encountered an issue while trying to pass a prop from the main Vue instance to a component. While one of the props is being successfully passed, the second one seems to be causing some trouble. Main Instance var app7 = new Vue({ el: &apos ...

How can I write the code to enable dragging the button for navigating to the next page?

<a draggable="true" class="user" id="leonardo" ondragstart="dragUser(this, event)" aria-selected="undefined"> IPD</a> If I want the button to navigate to the next page when dragged, what code should I write? ...

Type of JavaScript map object

While exploring TypeScript Corday, I came across the following declaration: books : { [isbn:string]:Book}={}; My interpretation is that this could be defining a map (or dictionary) data type that stores key-value pairs of an ISBN number and its correspon ...

The Gateway to Github: Unveiling the Mysteries through a

I need assistance in creating a static web page that can extract and showcase all the latest pull requests from a specified GitHub repository. My intention is to utilize octokit.js, but it seems to be designed for node.js. Is there any simple approach to ...

Issue with the height of content in Mobile Safari when using Bootstrap 4 columns

I have incorporated Bootstrap 4 into my website's design, specifically utilizing the bootstrap grid layout in flex mode. Within one of the columns, I have placed a button that I desire to fill the entire column width. I have achieved this by setting ...

Utilizing Multer for uploading images and videos

Could someone please help me understand why the first and last endpoints in my app.js file are working, but the third one isn't functioning as expected? Here are the files I'm working with: app.js const express = require('express'); c ...

Update the fuelux treeview after uploading a file

Currently, I am utilizing the jquery fileupload plugin to facilitate the process of uploading a file and then using the data from said file to populate a fuelux treeview. I have configured an ajax call for handling the file data where the information is fe ...

Create an array of arrays within a loop using TypeScript

My application contains an object with dates and corresponding time arrays. The console log output is displayed below: 32: { 1514160000: Array [ 1200, 1500 ], 1514764800: Array [ 1200, 1500 ], 1515369600: Array [ 1200, 1500 ], 1515974400: Array [ 700, 12 ...