Angular 1.5 component communication suggestions usually have output bindings to invoke methods on root controllers.
Let's say I have a root component, and two child components.
<root>
<child-1></child-1>
<child-2></child-2>
</root>
It'd like to react to a button click on component one by reading a value on component two and then doing something in the root.
For example, child-1 is a directive which wraps a drawing library that attaches a drawing to its DOM node and has a variable to control that drawing.
child-2 has a button. When it is clicked, data from the child-1 variable should be passed on to root which does something with it.
Specifically, child-1 wraps var graph2d = new vis.Graph2d(container, dataset, options);. Later on, I would like to retrieve some information from graph2d and pass it on to root to do something with it.
This boils down to: how can components react to events issued by other components? The inputs and outputs suggestions don't seem to cover that scenario.
In angular 1.5 you can use require and/or property bindings (input/output) to communicate.
If you use the require property then your root component would publish an api and your child component would get a reference to the controller:
angular.module('app').component('child1', {
bindings: {},
require: {api: '^root'}, //your <root> component
template: '',
controller: controller
});
You can then use the methods of the root component in your child component:
$ctrl.api.addWatchedBook();
This is the root component controller function:
$ctrl.addWatchedBook = addWatchedBook;
function addWatchedBook(bookName){
booksWatched.push(bookName);
}
Here is a complete architectual overview: Component Communications
Related
I'm creating a single page application (SPA) that uses Vue Router, therefore it is comprised mostly of Vue components with one blade component that puts it all together using
<router-view></router-view>
I want to know how I can pass data computed within my controller and pass it to a Vue component. The current way I'm doing it is by exposing extra API endpoints, for example in my controller I have:
public function countUsers()
{
$userCount = DB::table('users')->count();
return $userCount;
}
Then in api.php:
Route::get('usercount', 'UserMController#countUsers');
this way I can get the data within my Vue component using axios.get call to usercount.
Is there a better way of doing this? The data seems to take 1-2 seconds to display on the page and I can't imagine having this implementation for over 20 computations I need to do.
I've seen another method where you attach the data into the JavaScript context using the blade template, but I'm not sure how to get that to work for a SPA with Vue Routers.
get userCount in your controller and pass it to normal blade file. You can pass the variable in vue like below.
<router-view userCount="{{userCount}}"></router-view>
then for accessing userCount variable in vue, you can load this variable from props.
export default {
props: ['userCount'],
name: 'router-view',
},
mounted:function(){
let a = this;
this.userCount = JSON.parse(this.userCount)
}
for more information you should read the documentation first. It will help you understand thoroughly.
https://v2.vuejs.org/v2/guide/components-props.html
I have my user input as below in my html file:
<div class="form-group col-md-4">
<label for="btsIp"><strong>BTS IP:</strong></label> <input ngModel type="text"
name="btsIp" class="form-control" id="btsIp" (blur)="onChange()" [(ngModel)]="btsIp">
</div>
In my component.ts i am using it as
btsIp: any and passing it in my request
let Data = {
"btsIp": this.btsIp
}
which is working fine. But i want to pass this btsIp value to another page/Component where i need to call a request again where i need to pass the same btsIp value.
Could you all please help?
Passing data to the other page/component, it depends on whether it's the parent component, a sibling component, or a completely unrelated component in a different route.
Parent component: you can trigger a parent's component function by hooking on the #Output of the child component. Or you can access child component's properties via #ViewChild declaration. Read more: https://angular.io/guide/component-interaction
Sibling component: first transfer to the parent component as describe above, then pass the data from parent to child component via child's #Input.
A completely different page in a different route: you can pass the data via route params. Read more: https://angular.io/guide/router
Other approach: if you can afford using NgRx (state management inspired by Redux powered by RxJs for Angular), everything will be much easier once you mastered it, but that's a huge other topic that cannot be included in this answer box. More at https://github.com/ngrx/platform
Create a new ts File, inject that in to your module, use get and set
get IP (){
return this.btsIp;
}
set IP (btsIp){
this.btsIp= btsIp;
}
Hope it would help
If I have a template in a component that references non-existant components, angular 1.6 seems perfectly happy to render it as nothing at all. For example I have a route currently that looks like:
when('/something',{
title: 'Something',
template: "<mycomponent></mycomponent>",
})
If I forget to register mycomponent on my application, this route renders nothing. Is there some mode I can use in angular that will cause a harder error in a case like that? Or at least print something to the console when it occurs?
To be perfectly clear, I have this issue with both top level components referenced by the router, as well as other child components that those reference recursively.
No, there is no option for that. By the way "non rendered" components are a benefit IMO, because you could override this slot later.
A short example:
when('/something',{
title: 'Something',
template: "<slot><mycomponent></mycomponent></slot>",
})
assume you want to override the ui-part of mycomponent, just define a component for "slot"
There was a routeProvider.otherwise before. Not sure if it’s still supported. I’m on a phone so limited. Let me know how it goes.
UI Router supports components for routes, this means that it is capable of triggering an error if a component doesn't exist.
AngularJS currently doesn't offer component router. This means that route template is compiled as any other template with $compile, and unknown selectors are just ignored.
It is possible to patch ngRoute ngView directive to additionally check if a route that is expected to route to a component actually has it compiled.
// the whole list can be retrieved from commonly available sources
var htmlTags = ['p', 'div', ...];
app.directive('ngView', function () {
return function($scope, $element, $attrs) {
if (!DEBUG_MODE)
return;
if ($element.children().length !== 1)
return;
var routeComponent = angular.element($element.children()[0]);
var routeComponentTagName = routeComponent.prop('tagName').toLowerCase();
if (htmlTags.indexOf(routeComponentTagName) >= 0)
return;
var routeComponentName = $attrs.$normalize(routeComponentTagName);
if (!routeComponent.controller(routeComponentName)) {
console.warn(routeComponentTagName + ' element is non-standard yet not a component');
}
}
});
AngularJS already has $normalize() which is primarily intended for attributes and strips some specific prefixes, but as long as the components names don't have x or data prefix, it can work as generic kebab to camel case transformer.
There may be other ways to detect if a component was compiled on child element. The code above will trigger false negative if there already is parent routeComponentName component, because controller() travels up the hierarchy.
And the proper way to handle this problem is to provide test coverage for the application. Router-related cases should likely be handled in integration or e2e tests.
I have a structure:
Root component
buttons
(menu search component) - a simple input field
Widgets
(widget component )
(Cats widget) - displays what I put in menu search here.
How I pass data from menu search component to widget component?
User insert data in input field and I would like to displat in the widget field.
Do I have to call the event emitter from menu search and pass the data to buttons, and than go done widgets>Widget Child> cats component to display?
If so how do I correct pass the data? Espciall how do I pass the data downwards?
What I've currently done is used #Output to pass the data from cats to widgets, from widgets to root app.
To pass from child event I did
#Output() inputData: EventEmitter<string> = new EventEmitter<string>();
customFunction(event){
this.inputData.emit(event);
}
Than on the parent catch the event
<cats (inputData)="colorChange($event)"></cats>
until I reached Root component.
The angular guide has a bunch of tips around handling various component to component data interaction scenarios like this one.
The basic options are to chain property and output bindings between the intermediate components, use dependency injection and ViewChild decorators to 'jump' the view hierarchy and grab instances of your 'higher level' components from lower ones (dependency injection) or vice versa (ViewChild), or the use of services to pass data around (probably the best option in more varied situations due to less coupling to the view hierarchy).
See the angular docs for more info.
How can I access ember component's controller from another controller?
Is there a backdoor way like __container__.lookup just to know that there is this instance of component?
When I tried __container__.lookup with "component:<myComponentname>" it gave me an instance of component which is not being used anywhere in the application.
TL;DR
How to test Ember Component objects?
These lines of ember-inspector reveal how to get a "view registry," a mapping of DOM element ids to their respective Ember.Component instance in Ember 2.x, or Ember.View instance in 1.x.
viewRegistry: computed('application', function() {
return this.get('application.__container__').lookup('-view-registry:main') || View.views;
}),
So if you have an Ember component in your DOM like
<span id="ember1234">Hi I'm controlled by Ember</span>
you can look it up like
var viewRegistry = application.__container__.lookup('-view-registry:main') || View.views;
var myComponentInstance = viewRegistry.ember1234;