We are migrating old JavaScript projects into Angular 10.
There are many JavaScript functions calling from body onload. What is the best way to call such functions in Angular 10? Please help.
In Angular 10 you can call a javascript function on body load using ngOnInit() function
call the the function inside the ngOnInit() function .
like this
export class DashboardComponent implements OnInit {
constructor() {}
ngOnInit(): void {
this.checkNotifiactionToken(); //this is your custom function which is you want to call on body load
}
}
There should be a specific approach, when you are migrating old js body onload function. And you have multiple functions as well.
To keep it in mind angular component solution, I would suggest 1st to find which are the function required for which components.
let's suppose you have five function are in body onload.
One function required before even loading the app to get some configuration, move it to app initializer, you need to setup APP_INITIALIZER in angular.
Other two function required to load the 1st paint or home page. Move them to their respective components or you can use route resolver, if you have routing or ngOninit
The key point here to for better performance, in Angular we have multiple way to do it. You need to find that match where things required and fit.
Related
We have a requirement that we'd like to develop a "mini" testing framework for use within our Angular application. The point of the framework is to be able to manipulate API calls to alter the response body and status code in order to trip various error handlers within our application and make sure the application is responding correctly to errored API calls.
To do this I have been researching how to call Angular services from outside of Angular. This article describes how it is possible to create a service and then trigger it from outside Angular by calling the window.fireAngularEvent('sampleEventName', args) function.
However when I tried to do this via the browser, I get the following: Uncaught TypeError: window.fireAngularEvent is not a function
Here is my Angular service
export class GlobalApiTestingFrameworkService {
constructor() {
window['fireAngularEvent'] = (eventName, args) => {
console.log('fireAngularEvent : ' + eventName + ' : ' + args);
}
}
}
What do I need to do to be able to call the window.fireAngularEvent function? Do I need to define it outside of Angular within its own JS file? If so, what exactly do I include within the function body to allow it to communicate with the service? The article I linked isn't very clear.
The problem is due to the space in window['fireAngularEvent '] replace the defintion with window['fireAngularEvent'] and you'll be able to call window.fireAngularEvent without any issue.
Make sure that your service is instantiated at least one time.
To be sure You can use for example your service in AppComponent like that:
export class AppComponent {
constructor(private globalApiTestingFrameworkService: GlobalApiTestingFrameworkService){
}
}
for clarify next part: payU is the Internet payment operator
I have a serious problem with integration my Angular app with payU payments. I won't store or pass credit card's data (security reasons) so I choose widget.
The first problem is how to place the widget in the code. Documentation says that I should place script in the following way:
<script
src="https://secure.payu.com/front/widget/js/payu-bootstrap.js"
pay-button="#pay-button"
merchant-pos-id="145227"
shop-name="Nazwa sklepu"
total-amount="9.99"
currency-code="USD"
success-callback="test"
sig="250f5f53e465777b6fefb04f171a21b598ccceb2899fc9f229604ad529c69532">
</script>
How you probably know, you can't set script in your code in this way in Angular so I decided use little walkaround:
ngAfterViewInit(): void {
this.script = document.createElement('script');
this.script.setAttribute('src', 'https://secure.payu.com/front/widget/js/payu-bootstrap.js');
this.script.setAttribute('pay-button', '#pay-button');
this.script.setAttribute('merchant-pos-id', '145227');
this.script.setAttribute('total-amount', '9.99');
this.script.setAttribute('currency-code', 'USD');
this.script.setAttribute('success-callback', 'test');
this.script.setAttribute('sig', '4752ce2b163684a9c27cc0923ad46068c04da5d34329f5669ce73dcf96394558');
this.renderer.appendChild(this.el.nativeElement, this.script);
}
I know it's not a perfect solution (if you know better way to do this, please let me know in comment.
But the main problem is pass name of callback function to success-callback attribute. I prepared function in my component, like:
test(arg: any) {
console.log(arg);
}
But I can't get this name. I was trying:
this.script.setAttribute('success-callback', this.test.name);
but property name is empty. Is there a simple way to get real name of method (after typescipt translating) in my component?
BTW.
Adding simple js script to index.html and providing its name works, but i need to call service within my function.
I'm using Angular v7.
Explanation:
Ok, let's start by explaining the script. Since the script is being added in the global namespace, the success callback refers to a global function with the name 'test' in your above code.
So we need a reference to the angular component's 'test' function in the global namespace of your app, so that it can be accessed on success callback.
In your component:
import {NgZone} from '#angular/core';
constructor(private zone:NgZone){
window.callbackComponentRef = {
testFn: (args) => {
this.zone.run(() => { this.test(args); })
}
};
}
test() {
//Whatever code you want to run
}
Then use in script addition code
this.script.setAttribute('success-callback', 'callbackComponentRef.testFn');
I have a category dropdown(in parent js) whose subcategory fills on parent page load as well on dropdown change . subcategory will fill from child js method .I have to create child js instance twice . on page load and on dropdown down change.
I dont want to create object in document.ready or as global variable
where should i create child class object exactly so that it can be used all over ?
problem is that jquery not letting me call
$.getScript('../Reports/assets/js/BookingReports.js'
twice as it send error that child class name(BookingReports) identifier as already created .
class ReportsInterface extends ReportBase {
constructor() {
super();
this.fillSubCategory;
}
init() {
this.Categories();
}
Categories() {
//fill category
this.FillSubCategory();
}
FillSubCategory() {
if(!this.fillSubCategory) {
$.getScript(
'../Reports/assets/js/BookingReports.js',
function() {
this.fillSubCategory=new FillSubCategory("1");
obj.GetSubCategory();
}
)
}
}
}
$(document).ready(function() {
$("#ddlcategory").on('change', function() {
(new ReportsInterface()).showReportBooking();
})
})
i also tried to save object in parent class property but .cannot use it as object later on. how can I call child class method twice without creating any global variable ?
If you are using ES6, I would recommend not using JQuery to import separate files but rather using the ES6 import/export syntax.
I imagine the issue is that since $.getScript makes an http request to redownload the script file, it is actually running the script file twice (one for each download); in the second download, it will run into the naming conflict. ES6 import/exports would solve this issue for you, preventing BookingReport from being redefined.
You should be aware of a couple of things however:
(1) Using your JQuery setup, you get the benefit of lazy loading. To get the same in ES6, you'd have to use the slightly more complicated dynamic imports (see that same link above) -- for this app, however, it doesn't really look like you'd need that.
(2) You might want to familiarize yourself with a bundler like Webpack as this will do ahead-of-time importing and leave you with a single file to download rather than having to ping-pong back and forth from the server as you try to download all of the modularized files.
this is kind of relate to ExpressionChangedAfterItHasBeenCheckedError again.
in my situation, I have a parameter 'data' which I recover from ajax call.
this data is used to create child via #input directive. I wish the binding only occurs when data is defined. but I have no idea how to do that with angular
export class UserComponent{
data: any
constructor(
private userService: UserService){
this.userService.getUser()
.subscribe(result => {
this.data = result;
}
}
);
}
because the way it works, angular will display an ExpressionChangedAfterItHasBeenCheckedError, which I understand why, but how to ask angular to wait for the callback to be done and data to be != from undefined before start binding and stuff, the goal is to have some child initialized with the real value coming from the database.
If I should wait for the end of the cycle before binding "real" data, it's fine, but how to do it without having this error, (and please without using setTimeout as it looks a lot of rubbish !).
Thanks
<!--the template if it matter --><somechildtag [data]="data" ></somechildtag>
Load your component with ng-container.
For example:
<div *ngIf="data?.length > 0">
<ng-container *ngComponentOutlet="myChildComponent;
ngModuleFactory: childComponentsModule;"></ng-container>
</div>
So, you will render your child only if your data object is populated.
In your component:
private childComponentsModule: NgModuleFactory<any>;
constructor(private compiler: Compiler){
this.childComponentsModule = compiler.compileModuleSync(ChildComponentsModule);
}
You can see a more detailed example of how to load dynamically a component here:
Angular2: Use Pipe to render templates dynamically
Angular's documentation:
https://angular.io/docs/ts/latest/api/common/index/NgComponentOutlet-directive.html
I have a component which works fine using AJAX and mootools. Currently the view.raw.php only has one function in it which is display. I've been trying to create other functions within the component to use from AJAX but I can't make it work.
I thought that the ajax call is:
url: 'index.php?option=com_optical_database&view=gender&task=hello&format=raw',
with a public function within the component called hello:
public function hello(){
but it ignores this and goes to the display function every time. Is there a way of avoiding this?
Look at the place where the GET parameter task is used.
In Joomla there is usually a switch statement for this, and when you want to define a new task, you first need to add a new case in this switch.