Add angularjs component via service - angularjs

I am trying to add angularjs component using the code as per below. app.component doesn't work like this
Where as if I execute app.component from outsite it works.
How to fix this issue. Notice that the API will return component names. I just need to render them.
app.service('applookup', function($http) {
this.register = function() {
return $http.get('http://localhost:3003/api/provider/fetch/app1').then(function(res){
app.component('appleComponent', {
template : 'test'
});
return res.data.componentList;
});
}
});

As #William and #Zooly mentioned in comments. We can add reference to $compileProvider.component as per below in app.config
app.register = {
component : function(name, object) {
$compileProvider.component(name, object);
return (this);
}
Then use app.register.component to register the component

Related

AngularJS - Remove custom event listener

I have a non AngularJS snippet that is communicating with my AngularJS modules via custom events. Each of these AngularJS modules represents a different route. When I am leaving each route $onDestroy is triggered but does not remove the event listener. What am I missing to un-register my custom event?
Non AngularJS HTML Snippet
<script>
function sendEvent() {
const payload = getPayload();
const event = new CustomEvent('myCustomEvent', { payload });
window.dispatchEvent(event);
}
</script>
<button onclick="sendEvent()">Send Custom Event</button>
AngularJS Component
Class ModuleA {
$onInit() {
this.$window.addEventListener('myCustomEvent', this.onCustomEventClick.bind(this));
}
$onDestroy() {
this.$window.removeEventListener('myCustomEvent', this.onCustomEventClick.bind(this), false);
}
}
Class ModuleB {
$onInit() {
this.$window.addEventListener('myCustomEvent', this.onCustomEventClick.bind(this));
}
$onDestroy() {
this.$window.removeEventListener('myCustomEvent', this.onCustomEventClick.bind(this), false);
}
}
Every time you call bind it will create a new function and return it instead of modifying the function itself. So the even listeners you provide to addEventListener and removeEventListener are different functions, thus the registered ones are not removed.
To solve it, call bind once in $onInit and keep a reference to the returned function and always use that reference:
Class ModuleB {
$onInit() {
this.onCustomEventClick = this.onCustomEventClick.bind(this)
this.$window.addEventListener('myCustomEvent', this.onCustomEventClick);
}
$onDestroy() {
this.$window.removeEventListener('myCustomEvent', this.onCustomEventClick, false);
}
}

Angular v1 Component to Component data transfer

I'm struggling with a problem within Angular v1.6.1 where I am trying to transfer some data from a component to another component.
I have a component called navbar which resides in app\common\navbar has a controller that fetches data from a service. The following files make up navbar component
navbar.component.js
import controller from './navbar.controller';
import template from './navbar.html';
export default navbarComponent = {
restrict: 'E',
bindings: {},
template,
controller
};
navbar.controller.js
class NavbarController {
constructor(httpService) {
const dataUrl = "/assets/data/header.json";
this.name = 'Navbar';
this.headerData = {};
console.log("In "+this.name);
httpService.getData(dataUrl)
.then((response) => {
angular.extend(this.headerData,response.data);
},(error) => { throw error; });
}
}
export default NavbarController;
navbar.html
<section>
<top-header top-data="$ctrl.headerData"></top-header>
<section>
and my httpService resides in app\services folder. It fetches content using axios http library and looks something like this
httpService.js
import axios from 'axios';
export class HttpService {
constructor() {
this.name = "HttpService";
}
getData(api_url){
return axios.get(api_url)
.then((response) => response, (error) => error);
}
}
The component which uses my navbar component's headerData is top-header and resides in app\common\top-header. This is what it contains
top-header.component.js
import template from './top-header.html';
import controller from './top-header.controller';
export default topHeaderComponent = {
restrict: 'E',
template,
bindings: {
topData: '<'
},
controller,
};
top-header.controller.js
class TopHeaderController {
constructor() {
this.name = 'TopHeader';
this.topHeaderData = {};
this.$onInit = function() {
this.topHeaderData = this.topData;
console.log(this.topHeaderData);
console.log(this.topHeaderData.telephoneNumber);
console.log(this.topHeaderData);
}
}
}
export default TopHeaderController;
top-header.html
{{$ctrl.topHeaderData.telephoneNumber}}
and finally my static files resides in assets\data and the JSON I'm trying to fetch header.json contains
header.json
{
"telephoneNumber": 12345678
}
So the problem now I see is that the data does show up in my top-header component but I'm not sure what's happening but the data disappears (comes up undefined) once I try to access the object property.
What I'm saying is that in top-header.controller.js
when I console.log(this.topHeaderData); it shows the object but when I try to console.log(this.topHeaderData.telephoneNumber); it comes up undefined
I think the problem exists because of the execution priority of the Directives. I even set navbar component priority to 5 and it didn't help as the data is undefined.
top-header.controller.js
this.$onInit = function() {
this.topHeaderData = this.topData;
console.log(this.topHeaderData); // shows topData
console.log(this.topHeaderData.telephoneNumber); // undefined
console.log(this.topHeaderData); // shows topData
}
This data this.topHeaderData.telephoneNumber is essential as I use this in my template.
How can I resolve this issue? Any help would be greatly appreciated.
The problem may be in top-header.controller.js: you're assigning binded topData to this.topheaderData in $onInit hook but when component is initialized the data hasn't been fetched yet. Instead of $onInit you should use $onChange hook method which is called by Angular when binded property is updated (in your case when data is fetched from server)
Angular component docs:
$onChanges(changesObj) - Called whenever one-way bindings are updated.
The changesObj is a hash whose keys are the names of the bound
properties that have changed, and the values are an object of the form
{ currentValue, previousValue, isFirstChange() }. Use this hook to
trigger updates within a component such as cloning the bound value to
prevent accidental mutation of the outer value.

angularJS ES6 Directive

I am trying to develop an application in angular es6 . I have a problem with directve.
Here is my code
export default class RoleDirective {
constructor() {
this.template="";
this.restrict = 'A';
this.scope = {
role :"#rolePermission"
};
this.controller = RoleDirectiveController;
this.controllerAs = 'ctrl';
this.bindToController = true;
}
// Directive compile function
compile(element,attrs,ctrl) {
console.log("df",this)
}
// Directive link function
link(scope,element,attrs,ctrl) {
console.log("dsf",ctrl.role)
}
}
// Directive's controller
class RoleDirectiveController {
constructor () {
console.log(this.role)
//console.log("role", commonService.userModule().getUserPermission("change_corsmodel"));
//$($element[0]).css('visibility', 'hidden');
}
}
export default angular
.module('common.directive', [])
.directive('rolePermission',[() => new RoleDirective()]);
The problem is i couldn't get the role value inside constructor.
here is my html implementation
<a ui-sref="event" class="button text-uppercase button-md" role-permission="dfsd" detail="sdfdsfsfdssd">Create event</a>
If i console this it will get the controller object. But it will not get any result while use this.role.
Ok, so I managed to find out how this works.
Basically, the scope values cannot be initialized on the controller's constructor (because this is the first thing executed on a new object) and there is also binding to be considered.
There is a hook that you can implement in your controller that can help you with your use case: $onInit:
class RoleDirectiveController {
constructor () {
// data not available yet on 'this' - they couldn't be
}
$onInit() {
console.log(this.role)
}
}
This should work. Note that this is angular1.5+ way of doing things when not relying on $scope to hold the model anymore. Because if you use the scope, you could have it in the controller's constructor (injected).

AngularJS - Initialize form data based on value

I am trying to add edit functionality to my app. In one view, I have a button that brings you to the edit page.
<button ng-click="editMission(selectedMission.key)">Edit Mission</button>
The value selectedMission.key is used to determine what to initialize the edit page's form data with.
In the controller the function looks like this:
$scope.editMission = function(key){
$location.path('/edit');
}
On the edit page I have:
<div data-ng-init="editInit()">
And in my controller I have:
$scope.editInit = function(){
var query = myDataRef.orderByKey();
query.on("child_added", function(missionSnapshot){
if (missionSnapshot.key()==key){
...
}
});
}
How can I run the initialize function based on the key value from editMission. Should I use some getter/setter approach with a global key variable? I tried just placing the editInit code in editMission but the form data does not populate on view load.
Common practice is to use a service to share variables between views/controllers.
So in your case you would use the getter/setter approach as you suspected. I don't know what exactly you're trying to do, but the service in your case would look something like this:
app.factory('missionKeyService', function() {
var currentMission= {};
return {
setMissionKey: function(missionKey) {
currentMission.key = missionKey;
},
getMissionKey: function() {
return currentMission.key;
}
}
})
And in your controller1:
//include 'missionKeyService' in your controller function params
$scope.editMission = function(key) {
missionKeyService.setMissionKey(key);
$location.path('/edit');
}
And controller2:
//include 'missionKeyService' in your controller function params
$scope.editInit = function() {
var currentKey = missionKeyService.getMissionKey();
//do something with this key
...
}

AngularJS app inside ReactJS component?

Is it possible to create an Angular app inside a react component?
Something like:
React.createClass({
render: function() {
return <div ng-app>...</div>;
}
});
This is completely backwards, but will only have to be a temporary solution. I'm assuming I could do something like the code above, and add the angular bootstrapping to the componentDidMount lifecycle method.
Has anyone successfully done this?
Thanks.
It would look something like this:
componentDidMount: function(){
this._angularEl = document.createElement("div");
this._angularEl.innerHTML = angularTemplatHTMLString;
this._angularEl.setAttribute("ng-app", "");
this.getDOMNode().appendChild(this._angularEl);
// bind angular to this._angularEl
},
componentWillUnmount: function(){
// unbind angular from this._angularEl
this.getDOMNode().removeChild(this._angularEl);
delete this._angularEl;
},
render: function(){
return <div></div>
}
You could either use this for each component, or create a function which returns a mixin.
function makeAngularMixin(template){
return { /* above code except for render */ }
}
or have a component which allows passing an angular template via props.

Resources