|
1044 | 1044 | *
|
1045 | 1045 | */
|
1046 | 1046 |
|
| 1047 | +/** |
| 1048 | + * @ngdoc directive |
| 1049 | + * @name ngProp |
| 1050 | + * @restrict A |
| 1051 | + * @element ANY |
| 1052 | + * |
| 1053 | + * @usage |
| 1054 | + * |
| 1055 | + * ```html |
| 1056 | + * <ANY ng-prop-propname="expression"> |
| 1057 | + * </ANY> |
| 1058 | + * ``` |
| 1059 | + * |
| 1060 | + * or with uppercase letters in property (e.g. "propName"): |
| 1061 | + * |
| 1062 | + * |
| 1063 | + * ```html |
| 1064 | + * <ANY ng-prop-prop_name="expression"> |
| 1065 | + * </ANY> |
| 1066 | + * ``` |
| 1067 | + * |
| 1068 | + * |
| 1069 | + * @description |
| 1070 | + * The `ngProp` directive binds an expression to a DOM element property. |
| 1071 | + * `ngProp` allows writing to arbitrary properties by including |
| 1072 | + * the property name in the attribute, e.g. `ng-prop-value="'my value'"` binds 'my value' to |
| 1073 | + * the `value` property. |
| 1074 | + * |
| 1075 | + * Usually, it's not necessary to write to properties in AngularJS, as the built-in directives |
| 1076 | + * handle the most common use cases (instead of the above example, you would use {@link ngValue}). |
| 1077 | + * |
| 1078 | + * However, [custom elements](https://developer.mozilla.org/docs/Web/Web_Components/Using_custom_elements) |
| 1079 | + * often use custom properties to hold data, and `ngProp` can be used to provide input to these |
| 1080 | + * custom elements. |
| 1081 | + * |
| 1082 | + * ## Binding to camelCase properties |
| 1083 | + * |
| 1084 | + * Since HTML attributes are case-insensitive, camelCase properties like `innerHTML` must be escaped. |
| 1085 | + * AngularJS uses the underscore (_) in front of a character to indicate that it is uppercase, so |
| 1086 | + * `innerHTML` must be written as `ng-prop-inner_h_t_m_l="expression"` (Note that this is just an |
| 1087 | + * example, and for binding HTML {@link ngBindHtml} should be used. |
| 1088 | + * |
| 1089 | + * ## Security |
| 1090 | + * |
| 1091 | + * Binding expressions to arbitrary properties poses a security risk, as properties like `innerHTML` |
| 1092 | + * can insert potentially dangerous HTML into the application, e.g. script tags that execute |
| 1093 | + * malicious code. |
| 1094 | + * For this reason, `ngProp` applies Strict Contextual Escaping with the {@link ng.$sce $sce service}. |
| 1095 | + * This means vulnerable properties require their content to be "trusted", based on the |
| 1096 | + * context of the property. For example, the `innerHTML` is in the `HTML` context, and the |
| 1097 | + * `iframe.src` property is in the `RESOURCE_URL` context, which requires that values written to |
| 1098 | + * this property are trusted as a `RESOURCE_URL`. |
| 1099 | + * |
| 1100 | + * This can be set explicitly by calling $sce.trustAs(type, value) on the value that is |
| 1101 | + * trusted before passing it to the `ng-prop-*` directive. There are exist shorthand methods for |
| 1102 | + * each context type in the form of {@link ng.$sce#trustAsResourceUrl $sce.trustAsResourceUrl()} et al. |
| 1103 | + * |
| 1104 | + * In some cases you can also rely upon automatic sanitization of untrusted values - see below. |
| 1105 | + * |
| 1106 | + * Based on the context, other options may exist to mark a value as trusted / configure the behavior |
| 1107 | + * of {@link ng.$sce}. For example, to restrict the `RESOURCE_URL` context to specific origins, use |
| 1108 | + * the {@link $sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist()} |
| 1109 | + * and {@link $sceDelegateProvider#resourceUrlBlacklist resourceUrlBlacklist()}. |
| 1110 | + * |
| 1111 | + * {@link ng.$sce#what-trusted-context-types-are-supported- Find out more about the different context types}. |
| 1112 | + * |
| 1113 | + * ### HTML Sanitization |
| 1114 | + * |
| 1115 | + * By default, `$sce` will throw an error if it detects untrusted HTML content, and will not bind the |
| 1116 | + * content. |
| 1117 | + * However, if you include the {@link ngSanitize ngSanitize module}, it will try to sanitize the |
| 1118 | + * potentially dangerous HTML, e.g. strip non-whitelisted tags and attributes when binding to |
| 1119 | + * `innerHTML`. |
| 1120 | + * |
| 1121 | + * @example |
| 1122 | + * ### Binding to different contexts |
| 1123 | + * |
| 1124 | + * <example name="ngProp" module="exampleNgProp"> |
| 1125 | + * <file name="app.js"> |
| 1126 | + * angular.module('exampleNgProp', []) |
| 1127 | + * .component('main', { |
| 1128 | + * templateUrl: 'main.html', |
| 1129 | + * controller: function($sce) { |
| 1130 | + * this.safeContent = '<strong>Safe content</strong>'; |
| 1131 | + * this.unsafeContent = '<button onclick="alert(\'Hello XSS!\')">Click for XSS</button>'; |
| 1132 | + * this.trustedUnsafeContent = $sce.trustAsHtml(this.unsafeContent); |
| 1133 | + * } |
| 1134 | + * }); |
| 1135 | + * </file> |
| 1136 | + * <file name="main.html"> |
| 1137 | + * <div> |
| 1138 | + * <div class="prop-unit"> |
| 1139 | + * Binding to a property without security context: |
| 1140 | + * <div class="prop-binding" ng-prop-inner_text="$ctrl.safeContent"></div> |
| 1141 | + * <span class="prop-note">innerText</span> (safeContent) |
| 1142 | + * </div> |
| 1143 | + * |
| 1144 | + * <div class="prop-unit"> |
| 1145 | + * "Safe" content that requires a security context will throw because the contents could potentially be dangerous ... |
| 1146 | + * <div class="prop-binding" ng-prop-inner_h_t_m_l="$ctrl.safeContent"></div> |
| 1147 | + * <span class="prop-note">innerHTML</span> (safeContent) |
| 1148 | + * </div> |
| 1149 | + * |
| 1150 | + * <div class="prop-unit"> |
| 1151 | + * ... so that actually dangerous content cannot be executed: |
| 1152 | + * <div class="prop-binding" ng-prop-inner_h_t_m_l="$ctrl.unsafeContent"></div> |
| 1153 | + * <span class="prop-note">innerHTML</span> (unsafeContent) |
| 1154 | + * </div> |
| 1155 | + * |
| 1156 | + * <div class="prop-unit"> |
| 1157 | + * ... but unsafe Content that has been trusted explicitly works - only do this if you are 100% sure! |
| 1158 | + * <div class="prop-binding" ng-prop-inner_h_t_m_l="$ctrl.trustedUnsafeContent"></div> |
| 1159 | + * <span class="prop-note">innerHTML</span> (trustedUnsafeContent) |
| 1160 | + * </div> |
| 1161 | + * </div> |
| 1162 | + * </file> |
| 1163 | + * <file name="index.html"> |
| 1164 | + * <main></main> |
| 1165 | + * </file> |
| 1166 | + * <file name="styles.css"> |
| 1167 | + * .prop-unit { |
| 1168 | + * margin-bottom: 10px; |
| 1169 | + * } |
| 1170 | + * |
| 1171 | + * .prop-binding { |
| 1172 | + * min-height: 30px; |
| 1173 | + * border: 1px solid blue; |
| 1174 | + * } |
| 1175 | + * |
| 1176 | + * .prop-note { |
| 1177 | + * font-family: Monospace; |
| 1178 | + * } |
| 1179 | + * </file> |
| 1180 | + * </example> |
| 1181 | + * |
| 1182 | + * |
| 1183 | + * @example |
| 1184 | + * ### Binding to innerHTML with ngSanitize |
| 1185 | + * |
| 1186 | + * <example name="ngProp" module="exampleNgProp" deps="angular-sanitize.js"> |
| 1187 | + * <file name="app.js"> |
| 1188 | + * angular.module('exampleNgProp', ['ngSanitize']) |
| 1189 | + * .component('main', { |
| 1190 | + * templateUrl: 'main.html', |
| 1191 | + * controller: function($sce) { |
| 1192 | + * this.safeContent = '<strong>Safe content</strong>'; |
| 1193 | + * this.unsafeContent = '<button onclick="alert(\'Hello XSS!\')">Click for XSS</button>'; |
| 1194 | + * this.trustedUnsafeContent = $sce.trustAsHtml(this.unsafeContent); |
| 1195 | + * } |
| 1196 | + * }); |
| 1197 | + * </file> |
| 1198 | + * <file name="main.html"> |
| 1199 | + * <div> |
| 1200 | + * <div class="prop-unit"> |
| 1201 | + * "Safe" content will be sanitized ... |
| 1202 | + * <div class="prop-binding" ng-prop-inner_h_t_m_l="$ctrl.safeContent"></div> |
| 1203 | + * <span class="prop-note">innerHTML</span> (safeContent) |
| 1204 | + * </div> |
| 1205 | + * |
| 1206 | + * <div class="prop-unit"> |
| 1207 | + * ... as will dangerous content: |
| 1208 | + * <div class="prop-binding" ng-prop-inner_h_t_m_l="$ctrl.unsafeContent"></div> |
| 1209 | + * <span class="prop-note">innerHTML</span> (unsafeContent) |
| 1210 | + * </div> |
| 1211 | + * |
| 1212 | + * <div class="prop-unit"> |
| 1213 | + * ... and content that has been trusted explicitly works the same as without ngSanitize: |
| 1214 | + * <div class="prop-binding" ng-prop-inner_h_t_m_l="$ctrl.trustedUnsafeContent"></div> |
| 1215 | + * <span class="prop-note">innerHTML</span> (trustedUnsafeContent) |
| 1216 | + * </div> |
| 1217 | + * </div> |
| 1218 | + * </file> |
| 1219 | + * <file name="index.html"> |
| 1220 | + * <main></main> |
| 1221 | + * </file> |
| 1222 | + * <file name="styles.css"> |
| 1223 | + * .prop-unit { |
| 1224 | + * margin-bottom: 10px; |
| 1225 | + * } |
| 1226 | + * |
| 1227 | + * .prop-binding { |
| 1228 | + * min-height: 30px; |
| 1229 | + * border: 1px solid blue; |
| 1230 | + * } |
| 1231 | + * |
| 1232 | + * .prop-note { |
| 1233 | + * font-family: Monospace; |
| 1234 | + * } |
| 1235 | + * </file> |
| 1236 | + * </example> |
| 1237 | + * |
| 1238 | + */ |
| 1239 | + |
| 1240 | +/** @ngdoc directive |
| 1241 | + * @name ngOn |
| 1242 | + * @restrict A |
| 1243 | + * @element ANY |
| 1244 | + * |
| 1245 | + * @usage |
| 1246 | + * |
| 1247 | + * ```html |
| 1248 | + * <ANY ng-on-eventname="expression"> |
| 1249 | + * </ANY> |
| 1250 | + * ``` |
| 1251 | + * |
| 1252 | + * or with uppercase letters in property (e.g. "eventName"): |
| 1253 | + * |
| 1254 | + * |
| 1255 | + * ```html |
| 1256 | + * <ANY ng-on-event_name="expression"> |
| 1257 | + * </ANY> |
| 1258 | + * ``` |
| 1259 | + * |
| 1260 | + * @description |
| 1261 | + * The `ngOn` directive adds an event listener to a DOM element via |
| 1262 | + * {@link angular.element angular.element().on()}, and evaluates an expression when the event is |
| 1263 | + * fired. |
| 1264 | + * `ngOn` allows adding listeners for arbitrary events by including |
| 1265 | + * the event name in the attribute, e.g. `ng-on-drop="onDrop()"` executes the 'onDrop()' expression |
| 1266 | + * when the `drop` event is fired. |
| 1267 | + * |
| 1268 | + * AngularJS provides specific directives for many events, such as {@link ngClick}, so in most |
| 1269 | + * cases it is not necessary to use `ngOn`. However, AngularJS does not support all events |
| 1270 | + * (e.g. the `drop` event in the example above), and new events might be introduced in later DOM |
| 1271 | + * standards. |
| 1272 | + * |
| 1273 | + * Another use-case for `ngOn` is listening to |
| 1274 | + * [custom events](https://developer.mozilla.org/docs/Web/Guide/Events/Creating_and_triggering_events) |
| 1275 | + * fired by |
| 1276 | + * [custom elements](https://developer.mozilla.org/docs/Web/Web_Components/Using_custom_elements). |
| 1277 | + * |
| 1278 | + * ## Binding to camelCase properties |
| 1279 | + * |
| 1280 | + * Since HTML attributes are case-insensitive, camelCase properties like `myEvent` must be escaped. |
| 1281 | + * AngularJS uses the underscore (_) in front of a character to indicate that it is uppercase, so |
| 1282 | + * `myEvent` must be written as `ng-on-my_event="expression"`. |
| 1283 | + * |
| 1284 | + * @example |
| 1285 | + * ### Bind to built-in DOM events |
| 1286 | + * |
| 1287 | + * <example name="ngOn" module="exampleNgOn"> |
| 1288 | + * <file name="app.js"> |
| 1289 | + * angular.module('exampleNgOn', []) |
| 1290 | + * .component('main', { |
| 1291 | + * templateUrl: 'main.html', |
| 1292 | + * controller: function() { |
| 1293 | + * this.clickCount = 0; |
| 1294 | + * this.mouseoverCount = 0; |
| 1295 | + * |
| 1296 | + * this.loadingState = 0; |
| 1297 | + * } |
| 1298 | + * }); |
| 1299 | + * </file> |
| 1300 | + * <file name="main.html"> |
| 1301 | + * <div> |
| 1302 | + * This is equivalent to `ngClick` and `ngMouseover`:<br> |
| 1303 | + * <button |
| 1304 | + * ng-on-click="$ctrl.clickCount = $ctrl.clickCount + 1" |
| 1305 | + * ng-on-mouseover="$ctrl.mouseoverCount = $ctrl.mouseoverCount + 1">Click or mouseover</button><br> |
| 1306 | + * clickCount: {{$ctrl.clickCount}}<br> |
| 1307 | + * mouseover: {{$ctrl.mouseoverCount}} |
| 1308 | + * |
| 1309 | + * <hr> |
| 1310 | + * |
| 1311 | + * For the `error` and `load` event on images no built-in AngularJS directives exist:<br> |
| 1312 | + * <img src="thisimagedoesnotexist.png" ng-on-error="$ctrl.loadingState = -1" ng-on-load="$ctrl.loadingState = 1"><br> |
| 1313 | + * <div ng-switch="$ctrl.loadingState"> |
| 1314 | + * <span ng-switch-when="0">Image is loading</span> |
| 1315 | + * <span ng-switch-when="-1">Image load error</span> |
| 1316 | + * <span ng-switch-when="1">Image loaded successfully</span> |
| 1317 | + * </div> |
| 1318 | + * </div> |
| 1319 | + * </file> |
| 1320 | + * <file name="index.html"> |
| 1321 | + * <main></main> |
| 1322 | + * </file> |
| 1323 | + * </example> |
| 1324 | + * |
| 1325 | + * |
| 1326 | + * @example |
| 1327 | + * ### Bind to custom DOM events |
| 1328 | + * |
| 1329 | + * <example name="ngOnCustom" module="exampleNgOn"> |
| 1330 | + * <file name="app.js"> |
| 1331 | + * angular.module('exampleNgOn', []) |
| 1332 | + * .component('main', { |
| 1333 | + * templateUrl: 'main.html', |
| 1334 | + * controller: function() { |
| 1335 | + * this.eventLog = ''; |
| 1336 | + * |
| 1337 | + * this.listener = function($event) { |
| 1338 | + * this.eventLog = 'Event with type "' + $event.type + '" fired at ' + $event.detail; |
| 1339 | + * }; |
| 1340 | + * } |
| 1341 | + * }) |
| 1342 | + * .component('childComponent', { |
| 1343 | + * templateUrl: 'child.html', |
| 1344 | + * controller: function($element) { |
| 1345 | + * this.fireEvent = function() { |
| 1346 | + * var event = new CustomEvent('customtype', { detail: new Date()}); |
| 1347 | + * |
| 1348 | + * $element[0].dispatchEvent(event); |
| 1349 | + * }; |
| 1350 | + * } |
| 1351 | + * }); |
| 1352 | + * </file> |
| 1353 | + * <file name="main.html"> |
| 1354 | + * <child-component ng-on-customtype="$ctrl.listener($event)"></child-component><br> |
| 1355 | + * <span>Event log: {{$ctrl.eventLog}}</span> |
| 1356 | + * </file> |
| 1357 | + * <file name="child.html"> |
| 1358 | + <button ng-click="$ctrl.fireEvent()">Fire custom event</button> |
| 1359 | + * </file> |
| 1360 | + * <file name="index.html"> |
| 1361 | + * <main></main> |
| 1362 | + * </file> |
| 1363 | + * </example> |
| 1364 | + */ |
| 1365 | + |
1047 | 1366 | var $compileMinErr = minErr('$compile');
|
1048 | 1367 |
|
1049 | 1368 | function UNINITIALIZED_VALUE() {}
|
|
0 commit comments