AngularJs (1.5+) dynamic binding - javascript

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.

Related

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

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?

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

Proper way to delete ng-repeat item from child directive

So, I got the following generic structure:
<list-item ng-repeat="item in collection">
<remove-item>
<a ng-click="remove()">delete</a><!-- this is inside the view.html -->
</remove-item>
</list-item>
I need a proper way to, when triggered, the remove() function remove the full parent of the clicked .
I got this working calling scope.parent().parent()....remove() on the directive, but it is a shitty way to do that =P
Is there a better way? (sure there is).
Please, don't mind this lame question. I am new at AngularJs, and I am having a hard time trying to solve that. =(
Thank you in advance.
There are a few ways to avoid the $scope.$parent.$parent ... problem in Angular. If you are using scopes, you should put any callback or property that you want children to access in a sub-property of the scope. For example, in the parent directive, use $scope.api.remove = function() {...} rather than $scope.remove = function() {...}. Then you can call it in child directive like so:
<list-item ng-repeat="item in collection">
<remove-item>
<!-- remove() is bound to $scope.api rather than directly to $scope -->
<a ng-click="api.remove()">delete</a>
</remove-item>
</list-item>
The other way to do this would be to refactor your code to use controllers rather than scopes. This seems to have become the preferred way of doing things, and it is how Angular 2 works. This pattern is made especially easy by the new component feature in v1.5.0. I won't give a detailed example, but you can read more about this pattern here, and more about components here.

Custom Element issue: ref element is null in viewmodel

I have a custom element in Aurelia that uses a jQuery plugin under the hood (KendoUI). This custom element is being used within a view that uses the if.bind attribute.
The custom element uses an inline template, like so:
#inlineView('<template><input type="text" ref="proxy" class.bind="class"></template>')
Due to the nature of the jQuery plugin, I have to pass an element to initialize. I use the ref that I've defined in my template, like so:
$(this.proxy).doJQueryStuff(...)
After the element is detached, and then reattached, the ref element (this.proxy in my viewmodel) is null.
I initially thought that the problem was that since jQuery mutates the DOM, it was also mutating the view template. I thought that after the element is detached (and destroyed with a jQuery call to remove all KendoUI metadata), the input ref was no longer available resulting in an error upon reattachment because Aurelia was caching the view. However, this is not the case. It's been confirmed that Aurelia doesn't cache views unless you explicitly tell it to do so, and in this simplified plunk, the behavior is as expected.
Why would the reference to my ref element, in my viewmodel, be null after attaching and detaching the element?
Of note, the custom element is part of a page view, inside this construct:
<div id="application" class="au-animate" if.bind="isLoggedIn">
<nav-bar router.bind="router"></nav-bar>
<div class="page-host">
<router-view></router-view>
</div>
</div>
I don't know if anyone has run into any problems with a router-view inside of an if binding.
This issue was fixed this evening by this pull request. Run jspm update and confirm you have github:aurelia/templating-resources#0.17.3 installed.
The issue was the if template controller was not rebinding the view when re-attaching it to the DOM after it had been hidden.

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