move iframe width/height props to constants in MarkdownRenderer

This commit is contained in:
James Fenn
2022-01-21 11:30:37 -05:00
parent a55136de1a
commit a857557c78
11 changed files with 93 additions and 78 deletions

View File

@@ -70,7 +70,7 @@ export class ExampleInputComponent {
With only a bit of CSS, we have a visually appealing, A11Y friendly, and quirky input component. Look, it even wiggles the unicorns!
<iframe src="https://stackblitz.com/edit/angular-unicorns-text-input?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/angular-unicorns-text-input?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
Now, this component is far from feature complete. There's no way to `disable` the input, there's no way to extract data out from the typed input, there's not a lot of functionality you'd typically expect to see from an input component. Let's change that.
@@ -303,7 +303,7 @@ Finally, you can pass these options to `ngModel` and `formControl` (or even `for
If done properly, you should see something like this:
<iframe src="https://stackblitz.com/edit/angular-value-accessor-example?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/angular-value-accessor-example?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
# Form Control Classes
@@ -407,7 +407,7 @@ export class AppComponent {
}
```
<iframe src="https://stackblitz.com/edit/angular-value-accessor-dep-inject?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/angular-value-accessor-dep-inject?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
Not only do you have [a wide range of Angular-built validators at your disposal](https://angular.io/api/forms/Validators), but you're even able to [make your own validator](https://angular.io/api/forms/Validator)!

View File

@@ -54,7 +54,7 @@ While Angular templates come in many shapes and sizes, a simple but common use f
<p *ngIf="bool; else falseTemp">True</p>
```
<iframe src="https://stackblitz.com/edit/start-to-source-1-ng-template?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-1-ng-template?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
In this example, we are creating a template and assigning it to a [template reference variable](https://blog.angulartraining.com/tutorial-the-magic-of-template-reference-variables-3183f0a0d9d1). _This template reference variable makes `falseTemp` a valid variable to use as a value for other inputs in the same template._ It then handles that variable similarly to how a variable from the component logic is handled when referenced from the template.
@@ -80,7 +80,7 @@ But there's a ~~simpler~~ ~~much more complex~~ another way show the same templa
<ng-template [ngTemplateOutlet]="bool ? ifTrueCondTempl : falseTemp"></ng-template>
```
<iframe src="https://stackblitz.com/edit/start-to-source-2-conditional-render?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-2-conditional-render?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
> While this is not how the `ngIf` structural template works internally, this is a good introduction to the `ngTemplateOutlet` directive, which adds functionality to the `ng-template` tag.
>
@@ -129,7 +129,7 @@ Here, you can see that `let-templateVariableName="contextKeyName"` is the syntax
Now let's see it in action!
<iframe src="https://stackblitz.com/edit/start-to-source-3-context?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-3-context?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
As a quick note, _I only named these template input variables differently from the context value key to make it clear that you may do so_. `let-personName="personName"` is not only valid, but it also can make the code's intentions clearer to other developers.
@@ -157,7 +157,7 @@ export class AppComponent {
}
```
<iframe src="https://stackblitz.com/edit/start-to-source-4-viewchild?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-4-viewchild?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
> While this example is effectively not-much-more than an alternative API to `ngTemplateOutlet`, it serves as a basis for introducing into further concepts.
@@ -188,7 +188,7 @@ console.log(this.myComponent.inputHere); // This will print `50`
It would give you the property value on the instance of that component. Angular by default does a pretty good job at figuring out what it is that you wanted to get a reference of and returning the "correct" object for that thing.
<iframe src="https://stackblitz.com/edit/start-to-source-5-view-not-template?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-5-view-not-template?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
Despite the examples thus far having only used a string as the query for `ViewChild`, you're also able to use the ComponentClass to query for a component with that component type.
@@ -222,7 +222,7 @@ Now that we've configured the `ViewChild` to read this as an `ElementRef` (a cla
console.log(myComponent.nativeElement.dataset.getAttribute('data-unrelatedAttr')); // This output `"Hi there!"`
```
<iframe src="https://stackblitz.com/edit/start-to-source-6-read-prop?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-6-read-prop?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
`ViewChild` isn't an only child, though (get it?). There are other APIs similar to it that allow you to get references to other items in your templates from your component logic.
@@ -245,7 +245,7 @@ export class AppComponent {
}
```
<iframe src="https://stackblitz.com/edit/start-to-source-7-viewchildren?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-7-viewchildren?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
Would give you a list of all components with that base class. You're also able to use the `{read: ElementRef}` property from the `ViewChild` property decorator to get a `QueryList<ElementRef>` (to be able to get a reference to the DOM [Elements](https://developer.mozilla.org/en-US/docs/Web/API/Element) themselves) instead of a query list of `MyComponentComponent` types.
@@ -276,7 +276,7 @@ this.myComponents.changes.subscribe(compsQueryList => {
});
```
<iframe src="https://stackblitz.com/edit/start-to-source-8-querylist?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-8-querylist?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
It might be a good idea to gain familiarity of doing this as the Angular docs give the following warning in the [`QueryList` docs](https://angular.io/api/core/QueryList#changes):
@@ -356,7 +356,7 @@ export class CardsList implements AfterViewInit {
Awesome, let's spin that up and… Oh.
<iframe src="https://stackblitz.com/edit/start-to-source-9-cardlist-broke?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-9-cardlist-broke?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
The cards are still grey. Let's open up our terminal and see if the `console.log`s ran.
@@ -372,7 +372,7 @@ If we change the `ViewChildren` line to read:
@ContentChildren(ActionCard, {read: ElementRef}) actionCards;
```
<iframe src="https://stackblitz.com/edit/start-to-source-10-cardlist-fixed?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-10-cardlist-fixed?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
We'll see that the code now runs as expected. The cards are recolored, the `consoles.log`s ran, and the developers are happy.
@@ -620,7 +620,7 @@ Straightforward enough example, lets see a more difficult example:
<ng-template [ngTemplateOutlet]="testingMessage"></ng-template>
```
<iframe src="https://stackblitz.com/edit/start-to-source-11-broke-template-var?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-11-broke-template-var?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
If you look at the output of this example, you'll notice that `testingMessage` isn't rendering. This is because template reference variables bind to the view that they're present in; and as a result are unable to be accessed from parent views.
@@ -645,7 +645,7 @@ In order to fix this behavior, we'd need to move the second `ng-template` into t
</div>
```
<iframe src="https://stackblitz.com/edit/start-to-source-12-fixed-template-var?embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-12-fixed-template-var?embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
# The Bane of All JavaScipt Developer: Timings {#timings}
@@ -732,7 +732,7 @@ export class AppComponent implements DoCheck, OnChanges, AfterViewInit {
}
```
<iframe src="https://stackblitz.com/edit/start-to-source-13-lifecycle-explain?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-13-lifecycle-explain?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
Looking at the console logs, you'll be left with the following messages in your console:
@@ -781,7 +781,7 @@ export class AppComponent {
}
```
<iframe src="https://stackblitz.com/edit/start-to-source-14-static?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-14-static?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
Because this example does not have the `helloThereMsg` template within another view (outside of the host view), it is able to render without the errors we found when using `static: true`). Likewise, if you were to add an `OnInit` lifecycle method, you'd be able to get a reference to that template.
@@ -795,7 +795,7 @@ While you might wonder "Why would you use `static: false` if you can get the acc
When taking the example with the `testingMessageCompVar` prop and changing the value to `true`, it will never render the other component since it will always stay `undefined`.
<iframe src="https://stackblitz.com/edit/start-to-source-15-static-first-check?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-15-static-first-check?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
# View Manipulation {#view-manipulation}
@@ -837,7 +837,7 @@ export class AppComponent implements OnInit {
}
```
<iframe src="https://stackblitz.com/edit/start-to-source-16-createembeddedview?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-16-createembeddedview?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
This example has a lot going on, so let's dissect it bit-by-bit.
@@ -908,7 +908,7 @@ ngOnInit() {
}
```
<iframe src="https://stackblitz.com/edit/start-to-source-17-see-viewcontainer-indexes?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-17-see-viewcontainer-indexes?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
#### Context
@@ -951,7 +951,7 @@ To get around this, we can use the `ng-container` tag, which allows us to get a
```
<iframe src="https://stackblitz.com/edit/start-to-source-18-create-embedd-context?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-18-create-embedd-context?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
#### Move/Insert Template
@@ -965,7 +965,7 @@ const newViewIndex = 0;
this.viewContainerRef.move(embeddRef1, newViewIndex); // This will move this view to index 1, and shift every index greater than or equal to 0 up by 1
```
<iframe src="https://stackblitz.com/edit/start-to-source-19-move-template?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-19-move-template?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
Angular provides many APIs to take an existing view and move it and modify it without having to create a new one and run change detection/etc again.
@@ -980,7 +980,7 @@ ngOnInit() {
}
```
<iframe src="https://stackblitz.com/edit/start-to-source-20-insert-template?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-20-insert-template?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
[And in fact, this is how the `createEmbeddedView` works internally](https://github.com/angular/angular/blob/e1f6d1538784eb87f7497bef27e3c313184c2d30/packages/core/src/view/refs.ts#L174):
@@ -1026,7 +1026,7 @@ export class RenderTheTemplateDirective implements OnInit {
export class AppComponent {}
```
<iframe src="https://stackblitz.com/edit/start-to-source-21-directive-template?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-21-directive-template?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
You'll notice this code is almost exactly the same from some of our previous component code.
@@ -1058,7 +1058,7 @@ export class RenderTheTemplateDirective implements OnInit {
export class AppComponent {}
```
<iframe src="https://stackblitz.com/edit/start-to-source-22-directive-template-reference?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-22-directive-template-reference?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
## Input Shorthand {#directive-same-name-input}
@@ -1091,7 +1091,7 @@ export class AppComponent {}
> I want to make clear that this trick is present in all directives. If you name the input the same as the directive name, it will bind the value you're passing in to that directive name while also associating the directive with the component. No need for a separate input and directive name!
<iframe src="https://stackblitz.com/edit/start-to-source-23-directive-input-name?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-23-directive-input-name?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
Starting to look a bit more like the `ngTemplateOutlet`, no? Well, why not go even further! Let's lean into that!
With this syntax, we can add a second input, pass an object as the context to the template we want to render, and then a template reference variable, and be able to recreate Angular's `ngTemplateOutlet`'s API almost to-a-T:
@@ -1125,7 +1125,7 @@ export class RenderTheTemplateDirective implements OnInit {
export class AppComponent {}
```
<iframe src="https://stackblitz.com/edit/start-to-source-24-directive-outlet-alternative?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-24-directive-outlet-alternative?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
The nice part is that not only does it look like the directive from its usage, [but it's also not entirely dissimilar to how Angular writes the component internally](https://github.com/angular/angular/blob/e1f6d1538784eb87f7497bef27e3c313184c2d30/packages/common/src/directives/ng_template_outlet.ts#L35):
@@ -1188,7 +1188,7 @@ export class RenderThisDirective implements OnInit {
export class AppComponent {}
```
<iframe src="https://stackblitz.com/edit/start-to-source-25-structural-directive-intro?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-25-structural-directive-intro?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
[Just as we previously used Angular's dependency injection (DI) system to get a reference to the `ViewContainerRef`](#embed-views), we're using DI to get a reference to the `TemplateRef` created by the `*` in the invocation of this directive and embedding a view.
@@ -1206,7 +1206,7 @@ The cool part about structural directives, though? Because they're simply direct
</ng-template>
```
<iframe src="https://stackblitz.com/edit/start-to-source-26-structural-directive-manually-apply?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-26-structural-directive-manually-apply?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
It is for this reason that **only one structural directive can be applied to one element**. Otherwise, how would it know what order to wrap those directives in? What template should get what reference to what template?
@@ -1250,7 +1250,7 @@ export class AppComponent {
}
```
<iframe src="https://stackblitz.com/edit/start-to-source-27-render-if-intro?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-27-render-if-intro?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
Super cool! Image we kept developing this structural directive out, but you noticed while running your test (which you should totally have 👀) that toggling the checkbox doesn't actually show anything! This is because it's running the check once on `ngOnInit` and not again when the input changes. So let's change that:
@@ -1278,7 +1278,7 @@ export class RenderThisIfDirective {
}
```
<iframe src="https://stackblitz.com/edit/start-to-source-28-render-if-work-toggle-true?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-28-render-if-work-toggle-true?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
You'll notice that I removed the `OnInit` lifecycle and replaced it with an input `set`ter. We could have changed the lifecycle method to use `ngOnChanges` to listen for input changes, given that we only have one input, but as your directive adds more inputs and you want to maintain the local state, that logic can get more complex.
@@ -1294,7 +1294,7 @@ update(): void {
}
```
<iframe src="https://stackblitz.com/edit/start-to-source-29-render-if-fully-working?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-29-render-if-fully-working?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
Here, we're using the `clear` method on the parent view ref to remove the previous view when the value is false. Because our structural directive will contain a template only used for this directive, we can safely assume that `clear` will only remove templates created within this directive and not from an external source.
@@ -1393,7 +1393,7 @@ export class MakePigLatinDirective {
export class AppComponent {}
```
<iframe src="https://stackblitz.com/edit/start-to-source-30-microsyntax?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-30-microsyntax?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
This might look familiar. We're using the `$implicit` value from the context within our structural directive! However, [if you review the section we introduced that concept in](#template-context), you'll notice that the syntax here is different but similar from a template variable that would be used to bind the context from an `ng-template` tag.
@@ -1429,7 +1429,7 @@ export class AppComponent {}
```
<iframe src="https://stackblitz.com/edit/start-to-source-31-structural-named-context?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-31-structural-named-context?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
Just as before, we would use semicolons to split the definitions, then bind the external (as in: from the directive) context value of `original` to the local (this template) variable of `ogMsg`.
@@ -1461,7 +1461,7 @@ And then call them with the following template:
<ng-template [consoleThing]="'This is a warning from the 👻 of code future, refactor this please'" [warn]="true"></ng-template>
```
<iframe src="https://stackblitz.com/edit/start-to-source-32-console-non-structural-directive?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-32-console-non-structural-directive?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
This can be super useful for both providing concise APIs as well as provide further functionalities to said directive simply. Structural directives offer similar, although it comes with its own syntax and limitations due to the microsyntax API.
@@ -1501,7 +1501,7 @@ export class MakePigLatinDirective implements OnInit {
export class AppComponent { }
```
<iframe src="https://stackblitz.com/edit/start-to-source-33-pig-latin-microsyntax?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-33-pig-latin-microsyntax?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
You can see that I've had to tweak our previous pig latin directive example a bit.
@@ -1524,7 +1524,7 @@ Now, I remember when I was learning a lot of the structural directive stuff, I t
</p>
```
<iframe src="https://stackblitz.com/edit/start-to-source-34-pig-latin-non-binding?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-34-pig-latin-non-binding?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
I was not, however, greeted by praises on my PR making this change, but rather by an error in my console:
@@ -1554,7 +1554,7 @@ So if we did want to take the non-functional example above and fix it to not use
</ng-template>
```
<iframe src="https://stackblitz.com/edit/start-to-source-35-pig-latin-normal-directive?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-35-pig-latin-normal-directive?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
### `as` to preserve values in template variable
@@ -1586,7 +1586,7 @@ export class AppComponent {
}
```
<iframe src="https://stackblitz.com/edit/start-to-source-36-as-keyword?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-36-as-keyword?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
While this example can be seen clearly with this usage of `ngIf` , let's try to add it into our `pigLatin` example:
@@ -1594,7 +1594,7 @@ While this example can be seen clearly with this usage of `ngIf` , let's try to
<p *makePiglatin="'test'; let msg; casing 'upper' | uppercase as upperInUpper">{{upperInUpper}}: {{msg}}</p>
```
<iframe src="https://stackblitz.com/edit/start-to-source-37-pig-latin-as-keyword-broken?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-37-pig-latin-as-keyword-broken?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
In this example, we're expecting `'upper'` to be turned into `'UPPER'` by the `uppercase` pipe, then to be passed as the input to `makePiglatinCasing` and for the `$implicit` value of that context to be assigned to a local variable `msg`. If you load this, you'll noticed that the uppercased pig lattin displays as expected but the `upperInUpper` variable (which we expected to be `'UPPER'`) is undefined.
@@ -1608,7 +1608,7 @@ this.parentViewRef.createEmbeddedView(this.templ, {
});
```
<iframe src="https://stackblitz.com/edit/start-to-source-38-pig-latin-as-keyword?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-38-pig-latin-as-keyword?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
Now that we're exporting the output with the `as`, it should show on-screen as expected. So why is this? **Well, `as` exports the outputted value that it's bound to.** In this case, we're binding the value to `casing` (because that's what `'upper'` is being passed as an input to).
@@ -1818,7 +1818,7 @@ export class AppComponent {
}
```
<iframe src="https://stackblitz.com/edit/start-to-source-39-uni-for?ctl=1&embed=1&file=src/app/app.component.ts" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/start-to-source-39-uni-for?ctl=1&embed=1&file=src/app/app.component.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
- We're starting with enabling `uniFor` as the structural directive name
- Then we're defining an input to accept `of` as a key in the syntax (to match the `ngFor` structural directive syntax).

View File

@@ -78,7 +78,7 @@ ReactDOM.createRoot(rootElement).render(
When finished, you should be able to verify the version of React youre using with `{React.version}`
<iframe src="https://app.coderpad.io/sandbox?question_id=200107" width="704" height="500" loading="lazy"></iframe>
<iframe src="https://app.coderpad.io/sandbox?question_id=200107" loading="lazy"></iframe>
## Conclusion

View File

@@ -29,7 +29,7 @@ A great example of a set of components we'll use to demonstrate unidirectionalit
Let's take a look at a code sample that follows this unidirectionality first:
<iframe src="https://app.coderpad.io/sandbox?question_id=176771" width="704" height="500" loading="lazy"></iframe>
<iframe src="https://app.coderpad.io/sandbox?question_id=176771" loading="lazy"></iframe>
As you can see we're passing the `onChange` and value props to `SimpleForm`. This keeps our state consolidated inside of the `App` component rather than split between `App` and `SimpleForm`. Once you "submit" the form, `SimpleForm` calls `onDone` which changes the state stored inside of `App`. This in turn causes a re-render of `SimpleForm`.
@@ -94,7 +94,7 @@ export default function App() {
}
```
<iframe src="https://app.coderpad.io/sandbox?question_id=176773" width="704" height="500" loading="lazy"></iframe>
<iframe src="https://app.coderpad.io/sandbox?question_id=176773" loading="lazy"></iframe>
This code works, but has some inherent complexity issues. When you start expanding this component, this idea of separating your state and having to inspect the child reference from the parent makes development more difficult. Let's take a look visually how following the application logic is now more difficult with this pattern.
@@ -133,7 +133,7 @@ Understanding unidirectionality is integral to scaffolding scalable React applic
Now that we have a deeper understanding of unidirectionality, here's a challenge for you: Refactor the following components to better reflect unidirectionality in this coding pad.
<iframe src="https://app.coderpad.io/sandbox?question_id=176774" width="704" height="500" loading="lazy"></iframe>
<iframe src="https://app.coderpad.io/sandbox?question_id=176774" loading="lazy"></iframe>
The functionality of the app should be consistent with the previous version. Stuck?

View File

@@ -239,7 +239,7 @@ Weve covered a lot about list comprehension in Python today! Were able to
For example, given this sandbox code pad of a long and messy list comprehension, how can you refactor to remove all usage of list comprehensions? Avoid using `map`, `filter` or other list helpers, either. Simply use nested `for` loops and `if` conditionals to match the behavior as it was before.
<iframe src="https://app.coderpad.io/sandbox?question_id=177671" width="704" height="500" loading="lazy"></iframe>
<iframe src="https://app.coderpad.io/sandbox?question_id=177671" loading="lazy"></iframe>
This is an open-ended question meant to challenge your skills youve learned throughout the article!

View File

@@ -113,7 +113,7 @@ Thanks to the lack of rendering on data storage, it's particularly useful for st
}, [dataRef]);
```
<iframe src="https://stackblitz.com/edit/react-use-ref-mutable-data?ctl=1&embed=1" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/react-use-ref-mutable-data?ctl=1&embed=1" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
# Visual Timer with Refs {#visual-timers}
@@ -145,7 +145,7 @@ Let's take the example from before, but inside of the `setInterval`, we update a
Now, we'd expect to see the timer update from `1` to `2` (and beyond) as the timer continues to render. However, if we look at the app while it runs, we'll see some behavior we might not expect:
<iframe src="https://stackblitz.com/edit/react-use-ref-mutable-buggy-code?ctl=1&embed=1" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/react-use-ref-mutable-buggy-code?ctl=1&embed=1" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
This is because [the closure](https://whatthefuck.is/closure) that's passed to the `setInterval` has grown stale. This is a common problem when using React Hooks. While there's a simple solution hidden in `useState`'s API, let's solve this problem using mutations and `useRef`.
@@ -171,7 +171,7 @@ Because `useRef` relies on passing by reference and mutating that reference, if
}, [dataRef]);
```
<iframe src="https://stackblitz.com/edit/react-use-ref-mutable-fixed-code?ctl=1&embed=1" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/react-use-ref-mutable-fixed-code?ctl=1&embed=1" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
> * I would not solve it this way in production. `useState` accepts a callback which you can use as an alternative (much more recommended) route:
>
@@ -214,7 +214,7 @@ At the start of this article, I mentioned that `ref`s are not just a mutable dat
In this example, if we took a look at the `console.log` in the `useEffect`, we'd find [an `HTMLDivElement` instance](https://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement) in the `current` property. Open the following StackBlitz and look at the console value to confirm:
<iframe src="https://stackblitz.com/edit/react-use-ref-effect?ctl=1&embed=1" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/react-use-ref-effect?ctl=1&embed=1" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
Because `elRef.current` is now a `HTMLDivElement`, it means we now have access to [the entire `Element.prototype` JavaScript API](https://developer.mozilla.org/en-US/docs/Web/API/Element#Properties). As such, this `elRef` can be used to style the underlying HTML node:
@@ -230,7 +230,7 @@ Because `elRef.current` is now a `HTMLDivElement`, it means we now have access t
)
```
<iframe src="https://stackblitz.com/edit/react-use-ref-effect-style?ctl=1&embed=1" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/react-use-ref-effect-style?ctl=1&embed=1" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
## Alternative Syntax {#ref-function}
@@ -272,7 +272,7 @@ const App = () => {
);
```
<iframe src="https://stackblitz.com/edit/react-use-ref-effect-style-forward-ref-wrong-kinda?ctl=1&embed=1" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/react-use-ref-effect-style-forward-ref-wrong-kinda?ctl=1&embed=1" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
You might be wondering why I didn't call that property `ref` instead of `divRef`. This is because of a limitation with React. If we try to switch the property's name to `ref`, we find ourselves with some unintended consequences.
@@ -297,7 +297,7 @@ const App = () => {
);
```
<iframe src="https://stackblitz.com/edit/react-use-ref-effect-style-forward-ref-wrong?ctl=1&embed=1" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/react-use-ref-effect-style-forward-ref-wrong?ctl=1&embed=1" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
You'll notice that the `Container` `div` is not styled to have a `lightblue` background. This is because `elRef.current` is never set to contain the `HTMLElement` ref. As such, for simple ref forwarding, you cannot use the `ref` property name.
@@ -325,7 +325,7 @@ const App = () => {
Now that we are using `forwardRef`, we can use the `ref` property name on the parent component to get access to the `elRef` once again.
<iframe src="https://stackblitz.com/edit/react-use-ref-effect-style-forward-ref?ctl=1&embed=1" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/react-use-ref-effect-style-forward-ref?ctl=1&embed=1" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
# Class Component References {#class-ref}
@@ -379,7 +379,7 @@ const App = () => {
> }
> ```
<iframe src="https://stackblitz.com/edit/react-class-ref-instance?ctl=1&embed=1" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/react-class-ref-instance?ctl=1&embed=1" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
If you look at the `console.log` statement, you'll notice that it prints something like this:
@@ -464,7 +464,7 @@ function App() {
}
```
<iframe src="https://stackblitz.com/edit/react-class-ref-instance-custom-props?ctl=1&embed=1" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/react-class-ref-instance-custom-props?ctl=1&embed=1" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
# Unidirectional Flow {#unidirectional-flow}
@@ -637,7 +637,7 @@ export default function App() {
}
```
<iframe src="https://stackblitz.com/edit/react-use-imperative-handle-demo-pre?ctl=1&embed=1" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/react-use-imperative-handle-demo-pre?ctl=1&embed=1" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
As you can witness from the embedded demo it will focus you on the `Container` `div` when the application renders. This example does not use the `useImperativeHandle` hook but instead relies on the timing of `useEffect` to have the `ref`'s `current` already defined.
@@ -680,7 +680,7 @@ export default function App() {
}
```
<iframe src="https://stackblitz.com/edit/react-use-imperative-handle-demo-post?ctl=1&embed=1" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/react-use-imperative-handle-demo-post?ctl=1&embed=1" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
> If you look in the console, you'll find the `console.log` has run when `focus()` ran!
@@ -704,7 +704,7 @@ That said, you're not limited to simply the names of native APIs. What do you th
}, [elRef])
```
<iframe src="https://stackblitz.com/edit/react-use-imperative-handle-demo-useful?ctl=1&embed=1" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/react-use-imperative-handle-demo-useful?ctl=1&embed=1" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
> When your focus is set to the `Container` element, try typing in the ["Konami code"](https://en.wikipedia.org/wiki/Konami_Code) using your arrow keys. What does it do when that's done?
@@ -777,7 +777,7 @@ export default function App() {
}
```
<iframe src="https://stackblitz.com/edit/react-use-ref-effect-style?ctl=1&embed=1" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/react-use-ref-effect-style?ctl=1&embed=1" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
This code behaves as we might initially expect, not because we've done things properly, but instead, thanks to the nature of React's `useEffect` hook's timing.
@@ -811,7 +811,7 @@ export default function App() {
}
```
<iframe src="https://stackblitz.com/edit/react-use-ref-effect-bug-effect?ctl=1&embed=1" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/react-use-ref-effect-bug-effect?ctl=1&embed=1" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
Oh no! The background is no longer `'lightblue'`! Because we delay the rendering of the `div`, `elRef` is _not_ assigned for the initial render. Then, once it _is_ rendered, it mutates the `.current` property of `elRef` to assign the ref. Because mutations do not trigger a re-render (and `useEffect` only runs during renders), `useEffect` does not have a chance to "compare" the differences in value and, therefore, run the side-effect.
@@ -838,7 +838,7 @@ Confused? That's okay! So was I at first. I made a playground of sorts to help u
}, [minus]);
```
<iframe src="https://stackblitz.com/edit/react-use-ref-not-updating?ctl=1&embed=1" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/react-use-ref-not-updating?ctl=1&embed=1" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
> Open your console and take notes of what `console.log` runs when you change the respective values!
@@ -907,7 +907,7 @@ But, you're probably thinking that if it accepts a function, we could pass a cal
);
```
<iframe src="https://stackblitz.com/edit/react-use-ref-callback-styling?ctl=1&embed=1" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/react-use-ref-callback-styling?ctl=1&embed=1" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
> But hey! Wait a minute! Even though the `shouldRender` timing mismatch is still there, the background is being applied all the same! Why is the `useEffect` timing mismatch not causing the bug we were experiencing before?
@@ -934,7 +934,7 @@ That's true. However, you _can_ combine the two behaviors to make a callback tha
}, [elRef, shouldRender]);
```
<iframe src="https://stackblitz.com/edit/react-use-ref-callback-and-effect?ctl=1&embed=1" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/react-use-ref-callback-and-effect?ctl=1&embed=1" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
# `useState` Refs {#usestate-refs}
@@ -958,7 +958,7 @@ You can do this relatively trivially using callback refs to assign to a `useStat
}, [elRef])
```
<iframe src="https://stackblitz.com/edit/react-use-ref-callback-and-use-state?ctl=1&embed=1" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/react-use-ref-callback-and-use-state?ctl=1&embed=1" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
Now that the `ref` update causes a re-render, you can now _**safely**_ use the `ref` in `useEffect`'s dependency array.
@@ -977,7 +977,7 @@ Now that the `ref` update causes a re-render, you can now _**safely**_ use the `
}, [elNode])
```
<iframe src="https://stackblitz.com/edit/react-use-ref-callback-and-state-effect?ctl=1&embed=1" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/react-use-ref-callback-and-state-effect?ctl=1&embed=1" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
However, this comes at an offset cost of performance. Because you're causing a re-render, it will inherently be slower than if you were not triggering a re-render. There are valid uses for this, however. You just have to be mindful of your decisions and your code's usage of them.

View File

@@ -499,7 +499,7 @@ Lets say that we have the “patch” version of a software tracked. We want
How can you modify the code below to support the match version being listed out properly?
<iframe src="https://app.coderpad.io/sandbox?question_id=175664" width="704" height="500" loading="lazy"></iframe>
<iframe src="https://app.coderpad.io/sandbox?question_id=175664" loading="lazy"></iframe>
Youll know the code is working when youre able to output the following:

View File

@@ -469,7 +469,7 @@ However, as you can see, we're running `stopPropagation` on the event in the blu
You can see a running example of this here:
<iframe src="https://stackblitz.com/edit/event-bubbling-demo?ctl=1&embed=1&file=index.js&hideExplorer=1&hideNavigation=1" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/event-bubbling-demo?ctl=1&embed=1&file=index.js&hideExplorer=1&hideNavigation=1" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
### Capturing {#event-capturing}
@@ -510,7 +510,7 @@ This means that when the user clicks on the red square, you'll see the following
You won't see anything from the green square's `eventListener`, however.
<iframe src="https://stackblitz.com/edit/event-capture-demo?ctl=1&embed=1&file=index.js&hideExplorer=1&hideNavigation=1" width="704" height="500" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<iframe src="https://stackblitz.com/edit/event-capture-demo?ctl=1&embed=1&file=index.js&hideExplorer=1&hideNavigation=1" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
You'll also notice that if you click on the green square, you'll never see the `"A click handled on green using capture"` message. This is due to the `stopPropagation`, as mentioned before. The click is being registered on the red square first and then stopped on the blue square.

View File

@@ -65,7 +65,7 @@ window.customElements.define('hello-component', HelloElement);
<hello-component></hello-component>
```
<iframe src="https://app.coderpad.io/sandbox?question_id=194516" width="704" height="500" loading="lazy"></iframe>
<iframe src="https://app.coderpad.io/sandbox?question_id=194516" loading="lazy"></iframe>
There are two primary differences from the vanilla JavaScript example. First, we no longer need to use the `connectedCallback` to call `render`. The LitElements `render` function is called by Lit itself whenever needed - such as when data changes or for an initial render - avoiding the need to manually re-call the render method.
@@ -159,7 +159,7 @@ window.customElements.define('hello-component', HelloElement);
<hello-component></hello-component>
```
<iframe src="https://app.coderpad.io/sandbox?question_id=194518" width="704" height="500" loading="lazy"></iframe>
<iframe src="https://app.coderpad.io/sandbox?question_id=194518" loading="lazy"></iframe>
Yup, thats all. Lit allows you to bind elements by using the `@` sign and passing the function as a placeholder to the `html` tagged template. Not only does this look much HTML-like, it handles event cleanup, re-rendering, and more.
@@ -254,7 +254,7 @@ window.customElements.define('hello-component', HelloElement);
<hello-component val="Test"></hello-component>
```
<iframe src="https://app.coderpad.io/sandbox?question_id=194519" width="704" height="500" loading="lazy"></iframe>
<iframe src="https://app.coderpad.io/sandbox?question_id=194519" loading="lazy"></iframe>
## Attribute Reactivity
@@ -292,7 +292,7 @@ export class ChangeMessageElement extends LitElement {
}
```
<iframe src="https://app.coderpad.io/sandbox?question_id=181069" width="704" height="500" loading="lazy"></iframe>
<iframe src="https://app.coderpad.io/sandbox?question_id=181069" loading="lazy"></iframe>
# Reactive Data Binding
@@ -332,7 +332,7 @@ export class FormElement extends LitElement {
}
```
<iframe src="https://app.coderpad.io/sandbox?question_id=181090" width="704" height="500" loading="lazy"></iframe>
<iframe src="https://app.coderpad.io/sandbox?question_id=181090" loading="lazy"></iframe>
You may also notice that were binding both the users input and output to set and reflect the state. [This is exactly how other frameworks like React also expect you to manage user state](https://coderpad.io/blog/master-react-unidirectional-data-flow/).
@@ -449,7 +449,7 @@ window.customElements.define('change-message-component', ChangeMessageElement);
<change-message-component></change-message-component>
```
<iframe src="https://app.coderpad.io/sandbox?question_id=194520" width="704" height="500" loading="lazy"></iframe>
<iframe src="https://app.coderpad.io/sandbox?question_id=194520" loading="lazy"></iframe>
This works because properties and attributes are both created at the same time with Lit.
@@ -514,7 +514,7 @@ class TodoElement extends LitElement {
}
```
<iframe src="https://app.coderpad.io/sandbox?question_id=181092" width="704" height="500" loading="lazy"></iframe>
<iframe src="https://app.coderpad.io/sandbox?question_id=181092" loading="lazy"></iframe>
# Passing Functions
@@ -549,7 +549,7 @@ class TodoElement extends LitElement {
}
```
<iframe src="https://app.coderpad.io/sandbox?question_id=181093" width="704" height="500" loading="lazy"></iframe>
<iframe src="https://app.coderpad.io/sandbox?question_id=181093" loading="lazy"></iframe>
You will notice that were using a `filter` within our `render` method. Because this logic is within the `render` method, it will run on every UI update. This is important to note in case you have expensive operations: you should avoid running those within the render method.

View File

@@ -3,6 +3,7 @@ import { useMarkdownRendererProps } from "./types";
import Image, { ImageProps } from "next/image";
import Zoom from "react-medium-image-zoom";
import { getFullRelativePath } from "utils/url-paths";
import { EMBED_SIZE } from "../constants";
export const getMedia = ({ serverPath }: useMarkdownRendererProps) => {
return {
@@ -48,5 +49,17 @@ export const getMedia = ({ serverPath }: useMarkdownRendererProps) => {
/>
);
},
iframe: (props: React.IframeHTMLAttributes<HTMLIFrameElement>) => {
const { src, ...rest } = props;
return (
<iframe
width={EMBED_SIZE.w}
height={EMBED_SIZE.h}
loading="lazy"
{...rest}
src={src}
/>
);
},
};
};

View File

@@ -0,0 +1,2 @@
// default sizing used for iframes (MarkdownRenderer/media.tsx)
export const EMBED_SIZE = { w: 704, h: 500 };