Employing aspect.around while actively monitoring for methods invoking one another

Seeking a solution to run specific code around the put() and add() functions for Dojo stores, I encountered an issue with JSON REST stores where add() simply calls put():

add: function(object, options){
  options = options || {};
  options.overwrite = false;
  return this.put(object, options);
},

Using aspect.around() with add() causes my code to run twice if applied to stores created with a store that treats add() as a shortcut to put().

I understand that this is a common practice among most stores, but I want my solution to work seamlessly with any store, regardless of method nesting.

Dojo's Observable.js faces a similar challenge and handles it in the following manner:

function whenFinished(method, action){
    var original = store[method];
    if(original){
      store[method] = function(value){
        if(inMethod){
          return original.apply(this, arguments);
        }
        inMethod = true;
        try{
          var results = original.apply(this, arguments);
          Deferred.when(results, function(results){
            action((typeof results == "object" && results) || value);
          });
          return results;
        }finally{
          inMethod = false;
        }
      };
    }
  }
  
  whenFinished("put", function(object){
    store.notify(object, store.getIdentity(object));
  });

  whenFinished("add", function(object){
    store.notify(object);
  });

  whenFinished("remove", function(id){
    store.notify(undefined, id);
  });

The question remains: Is there a concise way to modify my current code to check if it's already within a method, thus preventing duplicate execution?

I attempted to streamline my code but ended up with a clumsy, makeshift solution. It seems like I'm overlooking something simpler...

This is my current code snippet:

topic.subscribe( 'hotplate/hotDojoStores/newStore', function( storeName, store ){

  aspect.around( store, 'put', function( put ){

    return function( object, options ){

      return when( put.call( store, object, options ) ).then( function( r ) {
        var eventName;
        var identity = store.idProperty;
        eventName = object[ identity ] ? 'storeRecordUpdate' : 'storeRecordCreate';

        topic.publish( eventName, null, { type: eventName, storeName: storeName, objectId: r[ identity ], object: object }, false );

      } );

    }
  });

  aspect.around( store, 'add', function( add ){
    return function( object, options ){

      return when( add.call( store, object, options ) ).then( function( r ) {

        var identity = store.idProperty;

        topic.publish('storeRecordCreate', null, { storeName: storeName, storeTarget: storeTarget, objectId: r[identity], object: object }, false }  );

      });
    }
  });
});

Answer №1

Here's my take on it... One thing that's bothering me about my approach is whether it's completely foolproof.

Let's say store.add() gets called twice in a row. Is there a scenario where the first call sets inMethod to true, and then the second call finds it set to true because the first one didn't have time to set it back to false yet?

This might only be possible if nextTick() is invoked between the two calls, right?

Or perhaps I'm just overcomplicating things? (That wouldn't be surprising...)

  topic.subscribe( 'hotplate/hotDojoStores/newStore', function( storeName, store ){

    var inMethod;

    aspect.around( store, 'put', function( put ){

      return function( object, options ){

        if( inMethod ){
          return when( put.call( store, object, options ) );
        } else {

          inMethod = true;

          try {
            return when( put.call( store, object, options ) ).then( function( r ) {
              var eventName;
              var identity = store.idProperty;
              eventName = object[identity] ? 'storeRecordUpdate' : 'storeRecordCreate';

              topic.publish( eventName, null, { type: eventName, storeName: storeName, objectId: r[identity], object: object }, false );

            });
          } finally {
            inMethod = false;
          }

        }

      }
    });

    aspect.around( store, 'add', function( add ){
      return function( object, options ){

        if( inMethod ){
          return when( add.call( store, object, options ) );
        } else {

          inMethod = true;

          try {

            return when( add.call( store, object, options ) ).then( function( r ) {

              var identity = store.idProperty;

              topic.publish('storeRecordCreate', null, { type: 'storeRecordCreate', storeName: storeName, objectId: r[identity], object: object }, false );

            });
          } finally {
            inMethod = false;
          }
        }
      }

    });

    aspect.around( store, 'remove', function( remove ){
      return function( objectId, options ){

        return when( remove.call( store, objectId, options ) ).then( function( r ) {

          topic.publish('storeRecordRemove', null, { type: 'storeRecordRemove', storeName: storeName, objectId: objectId }, false );

        });
      };
    });

  });

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

Combine large arrays

Hey, I'm encountering some issues while trying to merge large arrays in a React Native app. Specifically, I am attempting to implement infinite scroll on React Native. The issue arises when the array reaches 500+ items; every time I add more items, my ...

Error: Django unable to load jQuery library

Hey there! I have a template that includes my JavaScript code. However, when I view the template in a browser, it doesn't provide the interaction I was hoping for. Upon checking the console, I see the following error messages: Error: Bootstrap's ...

the term 'this' does not pertain to the user object within the mongoose model

Here is a snippet of my code that saves a user object to a database using Express: api.post('/signup', function (req, res) { var user = new User(); user.name = req.body.name; user.email = req.body.email; user.setPassword(req.body ...

A guide on updating URLs that are not enclosed within an anchor tag using JavaScript

In my current scenario, I am dealing with text that includes URL links presented in two different formats. www.stackoverflow.com <a href="http://www.stackoverflow.com">Stack over flow</a> My objective is to create a straightforward function ...

The YouTube Iframe API encountered an issue while attempting to send a message to an HTTP recipient. The recipient's origin

Encountering an error when using the YouTube Iframe API on Safari 9.1, OS X Yosemite Issue: Unable to post message to http://www.youtube.com. Recipient has origin https://www.youtube.com This problem only occurs in Safari, as other browsers like Firefo ...

IE displaying "slow script" alert due to Knockout malfunction

Within my grid of observables and computed observables, the first row serves as a multiplier for all subsequent rows. Users can modify this percentage rate and Knockout automatically updates all relevant values accordingly. Additionally, I require a textbo ...

Occasionally, the view fails to update following an $http request

Although this question has been posed multiple times before, none of the solutions seem to be effective for my issue. Controller app.controller('HomeController', function ($scope, $timeout, $http) { $scope.eventData = { heading: ...

I am looking to showcase images beside individuals' names or photos on my website in a vertical arrangement, similar to how it is done on Facebook

Looking for suggestions on how to display images uploaded by users on my webpage in a way similar to Facebook, with the user's photo displayed beside each image. Any recommendations or website links would be greatly appreciated. Thanks, Santosh Sahu ...

Apollo Client's useQuery function is causing unnecessary refetches when using Next.js' router.push method

Currently, I'm facing an issue where a query within a useQuery Apollo Client hook is being re-run unnecessarily every time Next.js's router.push function is triggered. The problem code snippet looks like this: const Parent = () => { useQuery ...

Issue with jQuery delegate and selector

I am attempting to assign a click event to all first anchor tags in all current and future divs with the "panels" class. My approach looks like this: $('#panel').delegate('.panels a:first', 'click', function(event) [...] How ...

Tips for adjusting the size of an HTML canvas to fit the screen while preserving the aspect ratio and ensuring the canvas remains fully visible

I'm working on a game project using HTML canvas and javascript. The canvas I am using has dimensions of 1280 x 720 px with a 16:9 aspect ratio. My goal is to have the game displayed at fullscreen, but with black bars shown if the screen ratio is not 1 ...

NodeJS module loading issue

Currently, I am attempting to utilize the resemblejs library () in order to compare two images. Despite creating a directory and adding resemblejs as a dependency, when running nodejs test.js, an error occurs: var api = resemble(fileData).onComplete(funct ...

The ng-switch function is not generating the desired code output

In my Ionic app, I have the following code snippet that I am currently viewing with ionic serve. However, when the initial ng-switch statement triggers... <span ng-switch="post.enclosure"> <span ng-switch-when="[]"> <p>def&l ...

Instructions on how to toggle the visibility of a div when hovering over a different a tag

To keep things simple, I'm looking to create a visibility toggle effect on a div when someone hovers over an anchor tag. Similar to the behavior of the four buttons on this example link: The issue I'm facing is that I want the div to appear or b ...

Error: JSON key data not present in rendering

Here is a JSON string I am working with: {"{\"nodeName\":\"abc\"}":[{"url":"abc","status":true},{"url":"abc","status":true}]," {\"nodeName\":\"pqr\"}":[{"url":"abc","status":true},{"url":"abc","status":true}]} ...

How about making an Ajax request for each item in the array?

I have a task to perform Ajax calls for each item in an array and then trigger another function once all the calls are completed. Adding complexity, I am incorporating Papa Parse into making the Ajax call. This is the code snippet: getCsvData: function( ...

Is there a framework available to animate Pseudo CSS elements?

Recently, I was working on developing a bar chart that utilized pseudo CSS elements (::before, ::after). While I successfully created bars that look visually appealing, I encountered a challenge when attempting to animate the height changes. Whenever I us ...

Archive a webpage with refreshed content using ajax

Is there a way to save a webpage that has been updated through an ajax request? I'm looking to preserve basecamp message threads, but exporting is not possible since I am not the account owner. When attempting to use the javascript command below: jav ...

Ways to include additional details in each row of an autocomplete feature

I have successfully implemented autocomplete for venues worldwide, but now I want to display the address of each venue below its name. For example, if the autocomplete suggests the venue name as ABCD, I want the address of that venue to appear right benea ...

Utilize IntelliJ's TypeScript/JavaScript feature to extract a method from all instances

I am relatively new to using IntelliJ Idea Ultimate 2020 and I am currently exploring the refactoring functionalities within the software. Is there a way to extract a method from a section of code and apply it to all instances easily and exclusively withi ...