Accessing a variable within a bound function using .bind() in Javascript/Typescript

I am facing an issue where I need to bind a variable to a callback function in Mongoose, but the function already has a parameter named "val" embedded in it. Whenever I try to use .bind() to add another value to the callback function, I end up losing the original "val" attribute. Is there a workaround that allows me to retain the original parameter and also add my variable using .bind()? Below is an example of my dilemma:

// Original code snippet retrieves "val" parameter from validator
const maxLengthValidator = (val: string): boolean => {
  if (val.length > 255) return false;
  return true;
};

const userSchema = new Schema({
  email: {
    type: String,
    required: true,
    // unique: true
    validate: [
      {
        validator: maxLengthValidator, // Includes "val" attribute from post request
        msg: 'too short'
      },
    ]
  },
  password: {
    type: String,
    required: true
  }
});

export default model('User', userSchema);

What I aim to achieve:

// Updated maxLengthValidator with an additional boundary parameter
const maxLengthValidator = (val: string, boundary: number): boolean => {
  if (val.length > boundary) return false;
  return true;
};

...
validate: [
  {
    validator: maxLengthValidator.bind(this, 255), // Facing issues as it requires specifying the string for "val" parameter
    msg: 'too short'
  },
]
...

This update would allow me to set a maximum length within the validator object.

Answer â„–1

Spices

Consider modifying your function so that instead of accepting two arguments, it only takes one argument and then returns a second function that accepts the second argument. This technique is commonly referred to as spices.

// flavorValidator :: number -> string -> boolean 
const flavorValidator = (limit: number) => (taste: string): boolean  => {
  if (taste.length > limit) return false;
  return true;
};

// ... later ...

  seasoning: flavorValidator(255);

This approach allows you to create various validators by calling the function: flavorValidator(10) will provide you with a validator for limiting taste to 10 characters. And since it's a function, you can also assign it to a variable:

//sauceTasteValidator :: string -> boolean
const sauceTasteValidator: (taste: string) => boolean = flavorValidator(10);

Switch parameters for partial allocation

Rather than receiving value first followed by max length, receive the length initially. It achieves the same outcome as currying but retains the option to accept two parameters:

const flavorValidator = (limit: number, taste: string): boolean => {
  if (taste.length > limit) return false;
  return true;
};

// ... later ...

  seasoning: flavorValidator.bind(this, 255);

The concept is similar. However, this method offers more versatility - you can either call the function with both parameters flavorValidator(10, food) or apply it partially with just one parameter. The latter results in essentially the same outcome as currying, as it generates a new function with the same signature:

//sauceTasteValidator :: string -> boolean
const sauceTasteValidator: (taste: string) => boolean = flavorValidator.bind(this, 10);

Despite the resemblances, spices are not equivalent to partial application. Additionally, it's feasible to curry a function of any arity (number of parameters) to enable processing of individual or multiple parameters at once. For instance, refer to _.curry in Lodash

function add4(a, b, c, d) {
  console.log(a + b + c + d);
}

const spiceAdd4 = _.curry(add4); 

spiceAdd4(1)(2)(3)(4);
spiceAdd4(1, 2, 3, 4);
spiceAdd4(1)(2, 3)(4);
spiceAdd4(1, 2, 3)(4);
spiceAdd4(1)(2, 3, 4);
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="5f33303031373018147b6e7d60776c79764b4a497535494"><strong>[email protected]</strong></a>/lodash.min.js"></script>

Partial application using a placeholder or from the right

You can maintain the current format and adjust partial applications. While Function#bind lacks flexibility, you can craft your own solution or opt for a library. Let's utilize Lodash again, which offers solid implementations for these cases:

Using a placeholder for partial application

This method enables skipping certain parameters when applying partially. Thus, you can skip the initial parameter and solely set the second one:

const flavorValidator = (taste, limit) => {
  if (taste.length > limit) return false;
  return true;
};

//sauceTasteValidator :: string -> boolean
const sauceTasteValidator = _.partial(flavorValidator, _, 10);

console.log(sauceTasteValidator("seasoningTooStrong"));
console.log(sauceTasteValidator("subtleFlavor"));
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="330f12110002110538060d01080d09">[email protected]</a>/lodash.min.js"></script>

Right-to-left partial application

Apply partial functions starting from the right side towards the left, initiating with setting limit:

const flavorValidator = (taste, limit) => {
  if (taste.length > limit) return false;
  return true;
};

//sauceTasteValidator :: string -> boolean
const sauceTasteValidator = _.partialRight(flavorValidator, 10);

console.log(sauceTasteValidator("seasoningTooStrong"));
console.log(sauceTasteValidator("subtleFlavor"));
<script src="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="68040704051920061c060013131614051204">[email protected]</a>/lodash.min.js"></script>

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

Can you explain the significance of the regular expression pattern /(?:^|:|,)(?:s*[)+/g in Javascript?

When it comes to Jquery, the regexp pattern is defined as follows: var rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g; This particular pattern is designed to match strings such as "abc,[" and "abc:[", while excluding instances like "abc^[". But what doe ...

jQuery selector unable to locate the specified class in the table row

After receiving an array of strings as a response from an SQL query, I am using JavaScript to dynamically add this data as rows to an HTML table: loadUsers: function() { . . . function displayUsersOnTable(response) { for(var i = ...

Filter a data array using a two-dimensional filter array that may change dynamically

Currently, I am facing a challenge where I need to filter a data array of objects using a two-dimensional filter array of objects. Here is a glimpse of my data array: dataArray = [{ Filter_GroupSize: "1" Filter_Time: "5-30" title: "Tools Test ...

Issue: Unhandled ReferenceError - onChangeAssignedGroup function is not declared within scope at HTMLSelectElement.onchange

Having difficulty calling a PHP script via JavaScript when the user changes the value in the "Assigned To Group" selection. The goal is to modify the option list of a yet-to-be-created "Assign to User" selection. An error message pops up stating that it d ...

Toggle the visibility of a div by clicking on another div in a

I have created a unique design where a div features a background image of a face, along with a paragraph, two buttons, and an input box inside it. While I know this question has been asked before, my scenario is slightly different. I want the div with the ...

Exploring the differences between Office Fabric UI's I[component]StyleProp and the I[component]Styles interface

The Office Fabric UI documentation provides two interfaces for each component, such as https://developer.microsoft.com/en-us/fabric#/components/nav includes INavStyleProps interface and INavStyles interface A component that implements INavStyleProps ...

Include a back button during the loading of a URL in an Electron application

Within my Electron application, I have implemented elements that, upon clicking, redirect to a URL. However, navigating back to the previous (local) page is not currently achievable. Is there a feasible method to incorporate a layered back button on top o ...

"Trouble with the accordion: How to make the first one open

Is there a way to make the first tab automatically expand when the page is refreshed? I want the General tab to be expanded by default like this: General (top header) (-) lorem ipsum (-) lorem ipsum doller amu site amu doller lorem ipsum (+) lorem i ...

Enclose Angular $resource requests that do not return POST data

Currently, I am working on enhancing my $resource requests by implementing a straightforward wrapper. The primary objective is to incorporate some logic before the request is actually sent. For guidance, I referred to an informative article authored by Nil ...

Exploring a JavaScript file with the power of JavaScript and HTML

I have a .js file that contains the following data (excerpt for brevity) var albums= "tracks":[ {"title":"Dunnock","mp3":"Birdsong-Dunnock.mp3", "lyrics":"The Dunnock or hedge sparrow has a fast warbling song often delivered from t ...

Leverage the power of function overloading in TypeScript for efficient code

How can function overloading be reused effectively in TypeScript? Consider a scenario where a function is overloaded: function apply(value: number): number; function apply(value: string): string; function apply(value: any): any { return value; } No ...

What is the process Wikipedia uses to transform keywords into clickable links?

Currently, I am working on a Node.js project involving a model called "tags". I am looking for a way to automatically turn any tags mentioned in comments into links leading to the relevant tag page. For instance, if a user types out "What is a chicken?", I ...

Distinguishing between creating controllers in AngularJS

I am a beginner in the world of AngularJS and I have come across two different examples when it comes to creating a controller. However, the one that is more commonly used doesn't seem to be working for me. The problem with the first example is that ...

What are some ways to streamline this D3 script?

My CSV data displays pass rates by organisation for different years: org,org_cat,2004_passed,2004_total,2005_passed,2005_total,2006_passed,2006_total GSK,industry,35,100,45,100,55,100 I am using D3 and aiming to create a dictionary of organisations struc ...

Is it possible to run npm scripts directly?

There is a script in my package.json file "start": "cross-env NODE_ENV=development PORT=3000 CODE_SPLIT=0 node ./react-imvc/bin/www-babel-register", I need to run the script with the --inspect flag, but I am unable to modify the package.json. I would lik ...

Difficulty updating data in MongoDB using Angular and Express API

Currently engaged with a comprehensive MEAN stack project. I am attempting to append data to the "notes" array within my MongoDB document with ID #1. Here is a snapshot of the MongoDB document: > db.contacts.find().pretty() { "_id" : ObjectId("5a294af ...

changing size when hovered over with the mouse is not consistent between entering and exiting

Hi there, I'm currently utilizing the transform: scale(); property on a website and could use some assistance with a particular issue I haven't been able to find an answer for online. Here is the code snippet I'm working with: HTML: <d ...

remove a section from the main body

body { display: flex; justify-content: center; align-items: center; background: #0e1538; } <canvas id="spaceholder" width="804" height="604"></canvas> </div> <div class="MenĂ¼Center"> <canvas id="canvas" width="800" ...

Is it possible to extract the value from the JSON response using this.responseText?

Having trouble extracting data from a json response This is the HTML code I am using. index.html <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> </head ...

What is the process of creating and customizing popovers in Bootstrap 5 with jquery?

Is there a way to dynamically create and add content to Bootstrap 5 popovers using JavaScript or jQuery? In Bootstrap 3, I used the following method: $('#element').popover({ placement : 'left', trigger : 'focus', html: true } ...