How can I adhere to Angular 2's naming convention for Input and Output as suggested by the styleguide?

Working with inputs and outputs while following Angular 2's styleguide naming convention

Initially, my directive was defined like this:

...
inputs: [
'onOutside'
]
... 

export class ClickOutsideDirective {
@Output() onOutside: EventEmitter<any> = new EventEmitter();
}

However, the styleguide recommends not using the prefix on for outputs, as Angular 2 supports the on- syntax in templates.

Attempting to adjust it to:

@Input() outsideClick: any;
@Output() outsideClick: EventEmitter<any> = new EventEmitter();

But struggling to differentiate between the @Input and Output names without the on prefix.

In the previous approach, naming both the @Input and @Output the same worked, but errors occur when declared within the exported class.

Renaming @Input to outside and @Output to outsideClick seems counterintuitive since they represent the same function. outside is the action triggered by outsideClick.

Furthermore, if outside and outsideClick are no longer named identically, outsideClick may not know which function to execute.

How can I effectively name the @Input and @Output variables so that functionality is maintained while making sense, similar to the original example?

EDIT:

Example of how to use:

<div clickOutside [exceptions]="['.toggler']" (outside)="doSomethingOnOutsideClick()"></div> 

Answer №1

Avoid using the on prefix in JavaScript events; only event handlers should start with on. There is no onClick event in JS - instead, use the click event and assign a function to onClick for it to be called upon receiving the click event.

It's beneficial to name corresponding inputs and outputs when they are related.

@Input() name:any; 
@Output() nameChange: EventEmitter<any> = new EventEmitter();;

This enables Angular2's "two-way binding" shorthand.

[(name)]="someProp"

If you utilize @Input() and @Output() (the preferred method), there is no need for both inputs: [] and outputs: [] as they serve the same purpose, rendering one redundant.

To conform to the browser naming convention, consider:

(nameChange)="onNameChange($event)"

This allows an event handler named onNameChange to be triggered upon receiving the nameChange event.

If the event is not tied to an input/output pair, it may be best to omit the Change part.

(loggedIn)="onLoggedIn($event)

Answer №2

Indeed, the original poster posed multiple inquiries within a common framework, leading to distinct sections below.

Utilization and/or description

To enable support for Angular-2 and subsequent versions' "two-way binding", associate input with an output suffixed with Change, as shown:

@Input() password: string;
@Output() passwordChange: EventEmitter<string> = new EventEmitter();

This facilitates shorthand operation such as:

<app-my-component
    [(password)]="myPasswordProp"
    >
</app-my-component>

In the above example, I provide a default value to the component as input, while capturing user changes as output, essentially synchronizing myPasswordProp with MyComponent's internal state.

Nomenclature convention

In Angular-2 and later versions, reserve the "on" prefix exclusively for event handlers, not event emitters.

Note that using the "on" prefix for events is prohibited (and could result in compilation errors, particularly in newer Angular releases).

Even in JavaScript, there is no event named onClick; rather, it is referred to as click. The distinction lies in JS utilizing onClick as the attribute name where we assign event handlers, while Angular disallows this prefix.

Angular does permit the use of on for event handlers, like so:

(passwordChange)="onPasswordChange($event)"

Here, the onPasswordChange labeled event handler triggers upon activation of the passwordChange event.

However, if the event is not part of an input/output pair, skip the Change suffix when defining the output, opting instead for usage similar to:

(loggedIn)="onLoggedIn($event)"

Moreover, to adhere to browser-like naming conventions or differentiate events from other elements, our company adopted the "by" prefix, including examples like:

(byLogin)="onLogin($event)"

(bySave)="onSave($event)"

This method enhances readability, as it can be incorporated into human sentences, for instance:

  • "Our App's handler awaits action on login, spurred by login events originating from the library."

Conversely:

  • "The library's by login events trigger our App's handler, awaiting activity on login to transpire."

Readability serves as one rationale behind the utilization of both the "on" and "by" prefixes as implemented.

Class-based annotation vs Property-based annotation

Just as the initial post touched on this topic:

  • Employing @Input() and/or @Output() annotations with member variables stands as the preferred practice.

  • If you opt for the aforementioned approach, omit passing inputs: [] and/or outputs: [] to the class's annotation.

  • In essence, these two methods achieve analogous outcomes; employing one renders the other superfluous.

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

Is there a way to retrieve time data from a different server through AJAX?

I am in need of obtaining time information from an online source, whether it be an NTP server, JSON time server, or simply an HTTP Header. The precision is not important to me, but the requirement is that I must get the time from an online source. Unfortun ...

Breeze js requests metadata without needing to make a second call to the server

Currently, I am developing an Angular application that utilizes Breeze JS and ASP.NET OData controller. While testing, I encountered an issue where Breeze JS successfully makes the initial call to retrieve metadata from the server but fails to make the sec ...

Utilizing precise data types for return values in React hooks with Typescript based on argument types

I developed a react hook that resembles the following structure: export const useForm = <T>(values: T) => { const [formData, setFormData] = useState<FormFieldData<T>>({}); useEffect(() => { const fields = {}; for (const ...

Tips for broadcasting a router event

Currently, I am working with 2 modules - one being the sidenav module where I can select menus and the other is the content module which contains a router-outlet. I am looking for the best way to display components in the content module based on menu selec ...

Adjust the color of a contenteditable div once the value matches

I currently have a table with some contenteditable divs: <div contenteditable="true" class="change"> This particular JavaScript code is responsible for changing the color of these divs based on their content when the page loads. However, I am now ...

Encountered an issue with formControlName being undefined during the render process in Angular 2

I encountered an issue while implementing Reactive form validation following the official Angular documentation. The error message "username not defined" is causing trouble in my project. Here's the detailed error: Error: Uncaught (in promise): Error: ...

The login form is experiencing issues with submission when utilizing the submitFormHandler in ReactJS

In my single-page application, I'm working on creating a separate login page that will redirect the authenticated user to the main application. However, I'm encountering an issue where my submitFormHandler is not being invoked. The purpose of aut ...

What is the reason onbeforeunload does not fire requests in Safari browser?

Is there a way to ensure that data is saved to the database when a user interacts with the page and also when they refresh it? I have tried using onbeforeunload event, but Safari does not wait for the server request to finish before reloading the page, c ...

Is it possible for member variables to be reinitialized when clicking on a Component? Are there any alternative methods to prevent this from happening

How can I prevent the productList array in the CartComponent from being reinitialized when clicking on the cart tab after adding items to it through addItem function? export class CartComponent implements OnInit { public productList: any[] = []; ...

Determine whether I am verified or if the XMLHttpRequest has been directed

When making an XMLHttpRequest to an API secured with OAuth authentication, I encountered a situation where calling the API from a browser without being logged in automatically redirected me to the provider's login page. However, when attempting to ca ...

Unable to retrieve nested objects from HTTP Response

After receiving data from a HTTP Response, I am trying to access and display it in my template. However, despite storing the data into a component variable, I am encountering issues when trying to access specific properties of the object. { "files": [ ], ...

Utilizing shared functions defined across different controllers

Can I utilize the code within these controllers for other purposes? .controller('GenericController', ['$scope', '$controller', '$rootScope', '$dialogs', '$state', '$http', '$modal& ...

Tips for managing and authenticating communication between the backend and the frontend

I've built a backend system for user registration and login, but I'm struggling with handling and verifying sessions on the server side. Although I've read some guides on generating session tokens, I'm unsure about how to validate thes ...

Set a restriction on the Bootstrap DatePicker to only show dates within a

My application features StartDate and EndDate datepickers, and I need to implement a 30-day limit on the selection range to prevent performance issues caused by loading too much data. I'm looking for a functionality where if the user picks today as t ...

The current version of HTML5 Context Menus is now available

I'm in need of implementing the HTML5 Context Menu feature. Currently, only Firefox supports it. My main objective is to add some menu options without replacing the existing context menu. How can I achieve the same functionality now? I am aware of va ...

Always keep your phone in landscape orientation for optimal website viewing

Currently, I am facing an issue with my website where it functions perfectly on mobile devices in landscape orientation but elements get distorted when viewed in portrait mode. Is there a method to ensure that the website is always displayed in landscape ...

Creating a line break in a Vue.js confirmation dialog is a helpful feature that can be achieved with a

Is there a way to add a new line after the confirmation dialog question and insert a note below it? this.$dialog.confirm("Create Group","Would you like to create group "+ this.groupName +"?<br/>(NOTE: Selected project or empl ...

Transform the Material UI grid orientation to horizontal row for content display

I'm just starting out with material UI and I've put together a grid that includes two components - an autocomplete and a button. Right now, they're stacked on top of each other, but I want to align them side by side in a row. Here's the ...

A straightforward method of transmitting data from JavaScript to the Python back-end within a Streamlit application

Utilizing the st.components.v1.iframe, I integrated an authentication system that sends a token back to the parent when a user is authenticated. The iframe content is as follows: <script src="remote/auth.js"></script> <scri ...

Error in Angular integrating with Stripe. No definition found for 'Stripe'. Perhaps you meant 'stripe'?

I'm currently in the process of connecting Stripe to my app with redirection, utilizing Angular and typescript. My component contains the following code snippet: var head = document.getElementsByTagName('head')[0]; var script = document.cre ...