Using Inheritance with AngularJS Components - angularjs

I am using AngularJS components in anticipation of eventually moving to Angular2. I have a component (Component1) that is essentially a dropdown with a few specific inputs and outputs. I have another component (Component2) that is the exact same kind of dropdown, but has a dependency on the ng-model in Component1. Is there a way to use inheritance in Component2 so that I do not have a bunch of duplicate code?
I can see how to use inheritance in Angular2, so this seems to be the best approach. However, I can't find anything showing how to do this in Angular 1.5.
Component1 also requires a template, but it will be the same for both Component1 and Component2. Also, Component2 will require an additional input for the value from Component1, as well as some code in the $onChanges event when that additional input changes.
Thanks in advance!!

the best thing you can do is pass a model object to component 2 as bindings,
app..component('component2', {
bindings: {
modelObject: '<'
},
controller: function () {
//do stuff
}
});
inside html
<component2 model-object="$ctrl.modalObject"></component2>
when change occures in component1. if your component depends on that change
you need to use onchanges lifecycle hooks components.inside component2 controller
this.$onChanges=function(data){
//this data has all changed values..
// you can also use isFirstChange() to determine if it was the first or not.
if(data.hasOwnProperty('modalObject'){
if(!data.modalObject.isFirstChange()){//means its not the initialization}
}
}

Related

What's the actual cost of defining new function within react render method?

I'm trying to clarify the pros/cons of having a new function declaration within react's render method.
Consider a render method like the following:
render () {
return (<SomeComponent somePropWithoutEventBind={() => console.log('not so dangerous?')} />)
}
In the above example, somePropWithoutEventBind doesn't bind to a DOM event: react will check for prop changes and every time render is called this prop has changed - because it's a new function - so it never matches the previous, this is expensive but nothing tremendous.
Now in this case
render () {
return (<input onChange={() => console.log('dangerous?')} />)
}
onChange prop does bind to DOM (doing something like addEventListener) so every render will have to removeEventListener and addEventListener again? Is this the main reason behind avoiding to declare functions inside the render method?
If possible, please justify your answer pointing to react source code.
The main reason of avoiding defining new functions in render is to avoid over rendering.
Consider bind a new function onto a DOM element (react element not real DOM) like so: <button onClick={_ => this.setState({ hide: true })}>Hide Me</button>} there's almost none cost at all, since DOM elements gets re-rendered anyways. (site note: react doesn't use native DOM events like add/removeEventListener, it uses SyntheticEvent and your code targets virtual DOM aka react element not real DOM)
However for a custom components (In large codebase we typically have lots of complex Container Component composed of Functional/Class Child Components. Let's say you have something like
render() {
// you won't run into unnessary re-render issue
// when you use `onClick={this.handleClick}` since the function reference doesn't change
// while most perf tricks done by react bindings are relying on shallow compare of props/state
return (
<ComplexContainer onClick={_ => this.setState({ forceReRender: true})}>
<Child1 />
<Child2>
<NestedChild1 />
<NestedChild2 />
</Child2>
</ComplexContainer>
)
}
If you do this way, this will cause the whole render tree starting from ComplexContainer to re-render, this may have notable negative perf impacts, but you will need DevTools profiling to benchmark.
In fact, the real thing i wanna say is: it might not be that huge as you concern, avoid premature optimization can be more important. Give this awesome reading material a shot: React, Inline Functions, and Performance
A bit more info regarding react synthetic event system here, it's simply a wrapper of native DOM events to normalize the subtle differences of events among different browser vendors. The API would be the same event.preventDefault()/event.preventPropagation() etc works as it is, but you get cross-browser compatibility for free. Regarding how it works internally please see event delegation

How to load an Angular2 component from AngularJS more than one time?

I am working on an application which has both AngularJS and Angular. Right now, I am invoking Angular component from a html page using the below line:
System.import('app')
Inside app\app.module.ts file, I have specified a specific parent component to be bootstrapped. This parent component in turn invokes a child component. I put some console.log statements in the constructor of the parent and child component and I see everything works fine for the first time.
But, when I navigate away and comeback to the html page again, I notice that the parent and child components are not getting initialized. The only workaround I have found is to refresh the entire page which is not ideal. I tried to unload the Angular components as soon as the user navigates away but I couldn't find any suitable SystemJS methods.
I know Angular components gets initialized only once which is probably why this is happening but is there a way to get past this issue?
Thanks
I have managed to find an answer to my question. The trick is to use the fully qualified URL when importing and deleting the module like below:
System.import('protocol//domainname:portnumber/modulename/filename')
System.delete('protocol//domainname:portnumber/modulename/filename')
Hope this helps someone.
Maybe AngularJS bootstrap interfers with angular2.
https://angular.io/guide/upgrade#bootstrapping-hybrid-applications explains how bootstrap hybrid applications.
You can also try to migrate Angular 2 to Angular 5.
Well, this might be a long shot. But have you tried making your component to implement OnChanges and OnInit. You can call ngOnInit inside ngOnChanges to reinitialize the component again.
//this was my fix for a similar problem
In component, say:
#Component({
selector: 'app-myapp',
templateUrl: './myapp.component.html',
styleUrls: ['./myapp.component.scss']
})
export class MyappComponent implements OnInit, OnChanges {
ngOnChanges() {
ngOnInit(){}; //reinitialize when onchanges is called again
}
}
You should also consider https://angular.io/api/core/OnChanges#usage-notes.
hope it helps

How can I trigger a click on an element inside a child component (that I don't have access to)?

I have installed react-file-base64 into my React JS project and have implemented it like so:
import FileBase64 from 'react-file-base64';
import FileUpload from '../../forms/FileUpload'
...
class MyComponent extends Component {
render() {
return (
<FileUpload buttonText='Upload New Image'>
<FileBase64
multiple={ false }
onDone={ this.changeProfileImage }
/>
</FileUpload>
)
}
}
The code is obviously condensed for brevity.
As you can see, I've wrapped the FileBase64 component inside a custom FileUpload component - to do the old JS/CSS trick of hiding the file upload and triggering it via a different button press.
Given that I do not have direct access to edit the FileBase64 component, since it's been installed by NPM (and will possibly be updated by it in the future), and given that it is not a direct input element but rather a custom component that renders one - how can I trigger a click on the input element rendered by the FileBase64 component, from inside my FileUpload component?
You have a few options.
Reconsider using react-file-base64
This is a pretty minor NPM module, so ask yourself: is it worth using a few dozen lines of someone else's code instead of writing the functionality myself? Open source is amazing and leveraging other people's work can be a lifesaver, but learn to recognize when to lean on it and when not to.
Fork react-file-base64
Fork the original project and add whatever functionality you need to meet your requirements. Ideally do it in a well-written, well-documented way so that you can later open a pull request and contribute back to the project in a meaningful way.
Hack it a bit
It's good to stay inside of React as much as possible, but there are ways around it. You can, for example, still select DOM elements using plain old JavaScript. Remember that stuff? ;P
This would probably work fine - wrap the <FileBase64 /> component in a <div> that you can use to select any nested child <input> elements.
class MyComponent extends Component {
...
onBtnClick() {
this.inputWrapper.getElementsByTagName("input")[0].click();
}
render() {
return (
<FileUpload buttonText='Upload New Image' callback={this.onBtnClick} >
<div ref={(el) => this.inputWrapper = el} >
<FileBase64
multiple={ false }
onDone={ this.changeProfileImage }
/>
</div>
</FileUpload>
)
}
}
I dunno how exactly you're handling <FileUpload /> click callbacks but you get the idea. After a component renders, its DOM elements are laid bare for you to access. The trick is figuring out how to select those elements in the first place, and being careful that you don't break React in the process. But selecting an element and triggering a "click" event is pretty benign.
There are several triggers for this component that maybe suits your needs. Some of them are:
beforeUpload: Triggered before uploading. return true to continue or false to stop uploading.
doUpload: Triggered after the request is sent(xhr send | form submit).
onabort:riggered after you aborting a xhr.
uploadSuccess: Callback when upload succeed (according to the AJAX simply).
If you see the plugin documentation you can be how they work in detail, as well as more different events to interact with your input element inside your FileUpload component.

Angular 2 setting a new value does not trigger an input change event

I'm running into a weird case that only seems to happen upon first loading a component on a heavily based component page (loading 30+ components).
#Component{
selector: <parent-component>
template: `<child-component [myObject]=myObject>
}
export class ParentComponent {
private myObject:DTOValue;
constructor(service:MyService){
service.getDTOValue().subscribe((dtoValue:DTOValue) => {
this.myObject = dtoValue;
});
}
}
#Component{
selector: <child-component>
template: `<div></div>
}
export class ChildComponent {
#Input set myObject(value:DTOValue) => {//do something};
constructor(){
}
}
In this code, the Parent is going to get a value to a child as an input. This value comes from a request at a later time, so when the child is first initialized, the input could be undefined. When the value does get returned from the request and is set on the variable myObject, I'd expect that the child component would receive an input event being triggered. However, due to the timing, it seems like this is not always the case, especially when I first load a page that contains a lot of files being loaded.
In the case that the child component doesn't receive the input, if I click else where on my page, it seems to now trigger the change detection and will get the input value.
The 2 possible solutions I can think of that would require some large code changes so I want to make sure I choose the right now before implement them.
Change the input to be an Subject, so that I push the input value which should ensure that a correct event is triggered(this seems like overkill).
Use the dynamic loader to load the component when the request as return with the correct value (also seems like overkill).
UPDATE:
Adding a plnker: http://plnkr.co/edit/1bUelmPFjwPDjUBDC4vb, you can see in here that the title seems to never get its data bindings applied.
Any suggestions would be appreciated.
Thanks!
If you can identify where the problem is and appropriate lifecycle hook where you could solve it, you can let Angular know using ChangeDetectorRef.
constructor(private _ref: ChangeDetectorRef)
method_where_changes_are_overlooked() {
do_something();
// tell angular to force change detection
this._ref.markForCheck();
}
I had a similar issue, only with router - it needed to do redirect when/if API server goes offline. I solved it by marking routerOnActivate() for check...
When you trigger change detection this way a "branch" of a component tree is marked for change detection, from this component to the app root. You can watch this talk by Victor Savkin about this subject...
Apologize, the issue ended up being my interaction with jQuery. When I triggered an event for a component to be loaded, inside of the jQuery code, it wouldn't trigger the life cycle. The fix was after the code was loaded to then call for a change detection.

How to work with controllers for Extjs deeply nested components?

I have a large scale application with lots of views, models, stores in it. Till now i am able to manage all the functionality to run from functions, events withing the views itself. I have never used controller to handle the entire application.
Please let me know how to use controllers to handle each and every component in the app. And there are some components that are dynamically being generated. How to add listeners these components on demand.
Please tell me about controllers much!
Thanks in advance :)
Controllers use event selectors to handle events through an event bus, so handling events is built in to the component structure.
A controller typically looks like:
Ext.define('MyApp.controller.Foo', {
init: function() {
this.control({
'some_selector': {
someevent: this.onSomething
}
});
},
onSomething: function() {}
});
The selector is an Ext.ComponentQuery selector, so if a component that matches that selector fires a particular event, it will call your method. There's plenty of information about selectors in the docs.

Resources