Angular - dynamically inject content to <ng-content> component - javascript

I have composition of components
ComponentA
<div class="CA"><ng-content></ng-content></div>
ComponentB
<div class="CB"><ng-content></ng-content></div>
And in parent I want to use them like this:
<component-a>
<component-b>
// I want something here
<div>some-content injected from parent<div/>
</component-b>
</component-a>
So, my components are designed to be composable and parent requires access to all components from it's scope - without shadowing api.
What I want to do is also affect children of component-b from component-a. I want to access I want something here from ComponentA.component.ts and inject something there.
Real life example:
<app-input-with-buttons (onButtonClick)="someCallback()">
<app-input [validationMessage]="someValidation$ | async">
<input ngModel />
</app-input>
</app-input-with-buttons>
I need InputWithButtonsComponent to inject HTML to InputComponent children.
I know it "too React way", but this approach allows me to limit components to single responsibility, allowing form component to control each step of form control.
Is it possible to access many nesting levels of ng-content in Angular? Also, are there better architecture patterns for solutions like this?

Related

Recommended way of conditionally rendering custom Vue components

in my parent render function, I am rendering a list of form inputs. They can be number, slider, text, etc, and for each, I have a custom Vue component, i.e. FormInputSlider. I receive some data from an API, and then have an array of these different inputs to render. Doing a huge if/else block in my parent's render code seems unmaintainable, so what is the best/standard way of rendering a FormInputSlider component when I encounter a "form-input-slider" in the list iteration? I'm coming from a React understanding of the world for what it's worth.
If you've the component names, you could just use the built-in component tag to render the component dynamically :
<component :is="dynamicName" />
instead of :
<template v-if="dynamicName==='abc'">
<abc/>
</template>
<template v-elseif="dynamicName==='xyz'">
<xyz/>
</template>
....

Angular 5: creating a parent component with an external template and overriding the inner part

I'm trying to create some sort of parent component that gives me some general appearance and logic for all my components, but in which I can write some specific logic and templating inside.
Look at these images:
Both of these components have common traits: an upper part with a title and a "hide/show" button, and then, a "body" that differs between both of them. They also share that edit button and so, but my idea is to make that "body" part completely dynamic: that's the part of the component that I want to override with my implementation components.
In other words: I want to make an abstract class with Typescript that holds the template: the rectangle, the header and body, the title (which I want to override from the subclass)... and then, the "body" will be filled with the template provided by the subclass.
How can this be achieved in Angular? This far I've only seen ways of overriding completely the parent components templates, not to complement one with the other. I guess there must be a way to insert HTML code with Angular directives inside a component...
Thing is, which is it?
Thank you!
Let's assume you named your component CardComponent and your selector is app-card.
For the title
You can simply use the #Input() component decorator to get the title string and use it in your generic CardComponent, see the angular documentation: https://angular.io/guide/component-interaction
For the body:
You can create your component containing the header and Edit button and then use the <ng-content> tag to get what's inside the component selector, for example:
<h2>{{title}}</h2>
<ng-content></ng-content>
<button>Edit</button>
And so you can use your card component like this:
<app-card [title]="Channel select">
<!-- Insert your body html -->
</app-card>
PS: to learn more about ng-content, see this: https://medium.com/claritydesignsystem/ng-content-the-hidden-docs-96a29d70d11b

Where should I put data and methods within nested components?

I'm trying to understand how I can do the following flow in React
page load
ajaxA()
-return dataA
-render dropdown HTML
-ajaxB(dataA)
-return dataB
-render chart HTML
handleDropdownChange()
-ajaxB()
-return dataB
-render chart HTML
I have it split out into two components
a top section with controls (ajaxA returns data to build some dropdowns.
a couple of chart below. When one of the dropdowns in the top part changes, then the chart should update.
Should ParentApp contain all methods for updating the charts and data related to child components, passing both in as props, eg:
handleControlChange (event) {
this.setState(selectedOption: event.target.value)
},
render () {
return (
<ParentApp>
<Controls
handleControlChange={this.handleControlChange} />
<Chart />
</ParentApp>
)
}
or should that functionality live within the Controls component? The second way seems more reasonable to me but since Controls and Chart are siblings I'm not sure how I can pass data to Chart when there is a change within`Controls. As I understand it data only flows from parents to children in React. It seems like ParentApp would soon contain basically all the methods needed by its children components which kind of seems it goes against keeping components modular.
Where should I store my data and my methods to interact with it?
In principle React only lift the state up when this state must be shared between siblings and/or parent, when a child component doesn't need to send its state to parent or siblings it can have its own state and no lifting up is needed.
But practically speaking most apps will have state in central place at parent component, there are even libraries for central states like Redux , that being said we didn't lose modularity in any way because state is only part of the story, for example spliting the app into components will give you modularity in rendering, also because child components takes props you can reuse the same component in multiple places with different props to control its appearance almost the same way you change the appearance of an <a> link by just applying a class.

AngularJs (1.5+) dynamic binding

We are developing our own library of AngularJs (1.6.x) components/directives and we would like to have all HTML attributes that are specified on our components automatically and dynamically passed on to the underlying templates, without having to specify every single attribute as a binding.
For example, if I have a component like <my-component> with a template like <div class="my-component"></div> and I write in my HTML:
<my-component ng-required="ctrl.isRequired" ng-change="ctrl.onChange()" ng-attr-disabled="ctrl.isReadOnly"></my-component>
I want my template to render:
<div class="my-component" ng-required="ctrl.isRequired" ng-change="ctrl.onChange()" ng-attr-disabled="ctrl.isReadOnly"></div>
As I said above, we cannot know in advance all attributes, so they can't all be defined in the component bindings. The problem gets more complicated in Angular 1.5+, because replace has been deprecated, so the above template would render something like this:
<my-component ng-required="ctrl.isRequired" ng-change="ctrl.onChange()" ng-attr-disabled="ctrl.isReadOnly">
<div class="my-component" ng-required="ctrl.isRequired" ng-change="ctrl.onChange()" ng-attr-disabled="ctrl.isReadOnly"></div>
</my-component>
And also, when we have nested, deep hierarchies of components, we want the values to be passed down from the parent controllers to the (grand)children, i.e. the ctrl.onChange() method will be defined in the scope of the page controller where <my-component> is defined, but as each component in the hierarchy gets its own scope, as you go deeper, we want the method to still be callable.
I am relatively new to Angular, I hope the above make sense.

Nested components in Vue.js

I struggle in creating nested components where each layer includes templates:
<wizard>
<step name="first">Do this step first!</step>
<step name="second">This should follow</step>
</wizard>
(full example: http://jsfiddle.net/maxhq/9o4qxd7t/)
I only get templates to work either for parent or for child components, never for both.
if parent has no template and is used with <... inline-template>, child components (and their templates) are evaluated (like in http://jsfiddle.net/hajkrupo/3/)
if parent includes a template (even with special tag <content>), then the child components do not get inserted/evaluated
Can this be solved in vue.js?
If you're using the latest vue.js version (1.0.26 at the time of writing) your problem is using <content></content> as the syntax was changed to <slot></slot>
JSFiddle
No. inline-template means you define template inline there there:
When this param is present, the component will use its inner content as its template rather than transclusion content. This allows more flexible template-authoring.
You can do it this way: http://jsfiddle.net/8k335nrf/

Categories