Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

docs(ngProp, ngOn) #16627

Merged
merged 1 commit into from
Aug 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
319 changes: 319 additions & 0 deletions src/ng/compile.js
Original file line number Diff line number Diff line change
Expand Up @@ -1044,6 +1044,325 @@
*
*/

/**
* @ngdoc directive
* @name ngProp
* @restrict A
* @element ANY
*
* @usage
*
* ```html
* <ANY ng-prop-propname="expression">
* </ANY>
* ```
*
* or with uppercase letters in property (e.g. "propName"):
*
*
* ```html
* <ANY ng-prop-prop_name="expression">
* </ANY>
* ```
*
*
* @description
* The `ngProp` directive binds an expression to a DOM element property.
* `ngProp` allows writing to arbitrary properties by including
* the property name in the attribute, e.g. `ng-prop-value="'my value'"` binds 'my value' to
* the `value` property.
*
* Usually, it's not necessary to write to properties in AngularJS, as the built-in directives
* handle the most common use cases (instead of the above example, you would use {@link ngValue}).
*
* However, [custom elements](https://developer.mozilla.org/docs/Web/Web_Components/Using_custom_elements)
* often use custom properties to hold data, and `ngProp` can be used to provide input to these
* custom elements.
*
* ## Binding to camelCase properties
*
* Since HTML attributes are case-insensitive, camelCase properties like `innerHTML` must be escaped.
* AngularJS uses the underscore (_) in front of a character to indicate that it is uppercase, so
* `innerHTML` must be written as `ng-prop-inner_h_t_m_l="expression"` (Note that this is just an
* example, and for binding HTML {@link ngBindHtml} should be used.
*
* ## Security
*
* Binding expressions to arbitrary properties poses a security risk, as properties like `innerHTML`
* can insert potentially dangerous HTML into the application, e.g. script tags that execute
* malicious code.
* For this reason, `ngProp` applies Strict Contextual Escaping with the {@link ng.$sce $sce service}.
* This means vulnerable properties require their content to be "trusted", based on the
* context of the property. For example, the `innerHTML` is in the `HTML` context, and the
* `iframe.src` property is in the `RESOURCE_URL` context, which requires that values written to
* this property are trusted as a `RESOURCE_URL`.
*
* This can be set explicitly by calling $sce.trustAs(type, value) on the value that is
* trusted before passing it to the `ng-prop-*` directive. There are exist shorthand methods for
* each context type in the form of {@link ng.$sce#trustAsResourceUrl $sce.trustAsResourceUrl()} et al.
*
* In some cases you can also rely upon automatic sanitization of untrusted values - see below.
*
* Based on the context, other options may exist to mark a value as trusted / configure the behavior
* of {@link ng.$sce}. For example, to restrict the `RESOURCE_URL` context to specific origins, use
* the {@link $sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist()}
* and {@link $sceDelegateProvider#resourceUrlBlacklist resourceUrlBlacklist()}.
*
* {@link ng.$sce#what-trusted-context-types-are-supported- Find out more about the different context types}.
*
* ### HTML Sanitization
*
* By default, `$sce` will throw an error if it detects untrusted HTML content, and will not bind the
* content.
* However, if you include the {@link ngSanitize ngSanitize module}, it will try to sanitize the
* potentially dangerous HTML, e.g. strip non-whitelisted tags and attributes when binding to
* `innerHTML`.
*
* @example
* ### Binding to different contexts
*
* <example name="ngProp" module="exampleNgProp">
* <file name="app.js">
* angular.module('exampleNgProp', [])
* .component('main', {
* templateUrl: 'main.html',
* controller: function($sce) {
* this.safeContent = '<strong>Safe content</strong>';
* this.unsafeContent = '<button onclick="alert(\'Hello XSS!\')">Click for XSS</button>';
* this.trustedUnsafeContent = $sce.trustAsHtml(this.unsafeContent);
* }
* });
* </file>
* <file name="main.html">
* <div>
* <div class="prop-unit">
* Binding to a property without security context:
* <div class="prop-binding" ng-prop-inner_text="$ctrl.safeContent"></div>
* <span class="prop-note">innerText</span> (safeContent)
* </div>
*
* <div class="prop-unit">
* "Safe" content that requires a security context will throw because the contents could potentially be dangerous ...
* <div class="prop-binding" ng-prop-inner_h_t_m_l="$ctrl.safeContent"></div>
* <span class="prop-note">innerHTML</span> (safeContent)
* </div>
*
* <div class="prop-unit">
* ... so that actually dangerous content cannot be executed:
* <div class="prop-binding" ng-prop-inner_h_t_m_l="$ctrl.unsafeContent"></div>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't this one cause an error and break the example app?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it logs an error to the console, but doesn't stop execution

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it kills the current digest?

* <span class="prop-note">innerHTML</span> (unsafeContent)
* </div>
*
* <div class="prop-unit">
* ... but unsafe Content that has been trusted explicitly works - only do this if you are 100% sure!
* <div class="prop-binding" ng-prop-inner_h_t_m_l="$ctrl.trustedUnsafeContent"></div>
* <span class="prop-note">innerHTML</span> (trustedUnsafeContent)
* </div>
* </div>
* </file>
* <file name="index.html">
* <main></main>
* </file>
* <file name="styles.css">
* .prop-unit {
* margin-bottom: 10px;
* }
*
* .prop-binding {
* min-height: 30px;
* border: 1px solid blue;
* }
*
* .prop-note {
* font-family: Monospace;
* }
* </file>
* </example>
*
*
* @example
* ### Binding to innerHTML with ngSanitize
*
* <example name="ngProp" module="exampleNgProp" deps="angular-sanitize.js">
* <file name="app.js">
* angular.module('exampleNgProp', ['ngSanitize'])
* .component('main', {
* templateUrl: 'main.html',
* controller: function($sce) {
* this.safeContent = '<strong>Safe content</strong>';
* this.unsafeContent = '<button onclick="alert(\'Hello XSS!\')">Click for XSS</button>';
* this.trustedUnsafeContent = $sce.trustAsHtml(this.unsafeContent);
* }
* });
* </file>
* <file name="main.html">
* <div>
* <div class="prop-unit">
* "Safe" content will be sanitized ...
* <div class="prop-binding" ng-prop-inner_h_t_m_l="$ctrl.safeContent"></div>
* <span class="prop-note">innerHTML</span> (safeContent)
* </div>
*
* <div class="prop-unit">
* ... as will dangerous content:
* <div class="prop-binding" ng-prop-inner_h_t_m_l="$ctrl.unsafeContent"></div>
* <span class="prop-note">innerHTML</span> (unsafeContent)
* </div>
*
* <div class="prop-unit">
* ... and content that has been trusted explicitly works the same as without ngSanitize:
* <div class="prop-binding" ng-prop-inner_h_t_m_l="$ctrl.trustedUnsafeContent"></div>
* <span class="prop-note">innerHTML</span> (trustedUnsafeContent)
* </div>
* </div>
* </file>
* <file name="index.html">
* <main></main>
* </file>
* <file name="styles.css">
* .prop-unit {
* margin-bottom: 10px;
* }
*
* .prop-binding {
* min-height: 30px;
* border: 1px solid blue;
* }
*
* .prop-note {
* font-family: Monospace;
* }
* </file>
* </example>
*
*/

/** @ngdoc directive
* @name ngOn
* @restrict A
* @element ANY
*
* @usage
*
* ```html
* <ANY ng-on-eventname="expression">
* </ANY>
* ```
*
* or with uppercase letters in property (e.g. "eventName"):
*
*
* ```html
* <ANY ng-on-event_name="expression">
* </ANY>
* ```
*
* @description
* The `ngOn` directive adds an event listener to a DOM element via
* {@link angular.element angular.element().on()}, and evaluates an expression when the event is
* fired.
* `ngOn` allows adding listeners for arbitrary events by including
* the event name in the attribute, e.g. `ng-on-drop="onDrop()"` executes the 'onDrop()' expression
* when the `drop` event is fired.
*
* AngularJS provides specific directives for many events, such as {@link ngClick}, so in most
* cases it is not necessary to use `ngOn`. However, AngularJS does not support all events
* (e.g. the `drop` event in the example above), and new events might be introduced in later DOM
* standards.
*
* Another use-case for `ngOn` is listening to
* [custom events](https://developer.mozilla.org/docs/Web/Guide/Events/Creating_and_triggering_events)
* fired by
* [custom elements](https://developer.mozilla.org/docs/Web/Web_Components/Using_custom_elements).
*
* ## Binding to camelCase properties
*
* Since HTML attributes are case-insensitive, camelCase properties like `myEvent` must be escaped.
* AngularJS uses the underscore (_) in front of a character to indicate that it is uppercase, so
* `myEvent` must be written as `ng-on-my_event="expression"`.
*
* @example
* ### Bind to built-in DOM events
*
* <example name="ngOn" module="exampleNgOn">
* <file name="app.js">
* angular.module('exampleNgOn', [])
* .component('main', {
* templateUrl: 'main.html',
* controller: function() {
* this.clickCount = 0;
* this.mouseoverCount = 0;
*
* this.loadingState = 0;
* }
* });
* </file>
* <file name="main.html">
* <div>
* This is equivalent to `ngClick` and `ngMouseover`:<br>
* <button
* ng-on-click="$ctrl.clickCount = $ctrl.clickCount + 1"
* ng-on-mouseover="$ctrl.mouseoverCount = $ctrl.mouseoverCount + 1">Click or mouseover</button><br>
* clickCount: {{$ctrl.clickCount}}<br>
* mouseover: {{$ctrl.mouseoverCount}}
*
* <hr>
*
* For the `error` and `load` event on images no built-in AngularJS directives exist:<br>
* <img src="thisimagedoesnotexist.png" ng-on-error="$ctrl.loadingState = -1" ng-on-load="$ctrl.loadingState = 1"><br>
* <div ng-switch="$ctrl.loadingState">
* <span ng-switch-when="0">Image is loading</span>
* <span ng-switch-when="-1">Image load error</span>
* <span ng-switch-when="1">Image loaded successfully</span>
* </div>
* </div>
* </file>
* <file name="index.html">
* <main></main>
* </file>
* </example>
*
*
* @example
* ### Bind to custom DOM events
*
* <example name="ngOnCustom" module="exampleNgOn">
* <file name="app.js">
* angular.module('exampleNgOn', [])
* .component('main', {
* templateUrl: 'main.html',
* controller: function() {
* this.eventLog = '';
*
* this.listener = function($event) {
* this.eventLog = 'Event with type "' + $event.type + '" fired at ' + $event.detail;
* };
* }
* })
* .component('childComponent', {
* templateUrl: 'child.html',
* controller: function($element) {
* this.fireEvent = function() {
* var event = new CustomEvent('customtype', { detail: new Date()});
*
* $element[0].dispatchEvent(event);
* };
* }
* });
* </file>
* <file name="main.html">
* <child-component ng-on-customtype="$ctrl.listener($event)"></child-component><br>
* <span>Event log: {{$ctrl.eventLog}}</span>
* </file>
* <file name="child.html">
<button ng-click="$ctrl.fireEvent()">Fire custom event</button>
* </file>
* <file name="index.html">
* <main></main>
* </file>
* </example>
*/

var $compileMinErr = minErr('$compile');

function UNINITIALIZED_VALUE() {}
Expand Down
2 changes: 1 addition & 1 deletion src/ng/sce.js
Original file line number Diff line number Diff line change
Expand Up @@ -623,7 +623,7 @@ function $SceDelegateProvider() {
* | `$sce.CSS` | For CSS that's safe to source into the application. Currently unused. Feel free to use it in your own directives. |
* | `$sce.MEDIA_URL` | For URLs that are safe to render as media. Is automatically converted from string by sanitizing when needed. |
* | `$sce.URL` | For URLs that are safe to follow as links. Is automatically converted from string by sanitizing when needed. Note that `$sce.URL` makes a stronger statement about the URL than `$sce.MEDIA_URL` does and therefore contexts requiring values trusted for `$sce.URL` can be used anywhere that values trusted for `$sce.MEDIA_URL` are required.|
* | `$sce.RESOURCE_URL` | For URLs that are not only safe to follow as links, but whose contents are also safe to include in your application. Examples include `ng-include`, `src` / `ngSrc` bindings for tags other than `IMG` (e.g. `IFRAME`, `OBJECT`, etc.) <br><br>Note that `$sce.RESOURCE_URL` makes a stronger statement about the URL than `$sce.URL` or `$sce.MEDIA_URL` do and therefore contexts requiring values trusted for `$sce.RESOURCE_URL` can be used anywhere that values trusted for `$sce.URL` or `$sce.MEDIA_URL` are required. |
* | `$sce.RESOURCE_URL` | For URLs that are not only safe to follow as links, but whose contents are also safe to include in your application. Examples include `ng-include`, `src` / `ngSrc` bindings for tags other than `IMG` (e.g. `IFRAME`, `OBJECT`, etc.) <br><br>Note that `$sce.RESOURCE_URL` makes a stronger statement about the URL than `$sce.URL` or `$sce.MEDIA_URL` do and therefore contexts requiring values trusted for `$sce.RESOURCE_URL` can be used anywhere that values trusted for `$sce.URL` or `$sce.MEDIA_URL` are required. <br><br> The {@link $sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider#resourceUrlWhitelist()} and {@link $sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider#resourceUrlBlacklist()} can be used to restrict trusted origins for `RESOURCE_URL` |
* | `$sce.JS` | For JavaScript that is safe to execute in your application's context. Currently unused. Feel free to use it in your own directives. |
*
*
Expand Down