I wonder if I can modify a property that is in a component via an external controller.
That is, I have an injected component in index.html as follows:
{{ button-feed }}
This component is used in many views.
This component has to be hidden as I get values in the controller, and what I really want is that since this controller, modify a property that hides or shows the button.
The component has the form:
App.ButtonComponent = Ember.Component.extend ({
hideClass: false
});
The property hideClass is used to display or not the button. What I want is to modify this property but using a controller that does not belong to the component button.
I tried to access the property from outside the component, but it is impossible.
You can pass parameters to your component like this:
{{button-feed hideClass=true}}
{{button-feed hideClass=false}}
Also, you could pass in a controller property too.
{{button-feed hideClass=controllerProperty}}
To answer your comment, you can set the controllerProperty by using the code below. Since controllerProperty is bound to the hideClass on your component, changing controllerProperty will change hideClass.
controller.set('controllerProperty', false);
You can read more about setting properties on a controller here.
Related
I'm new to Angular, sorry if my questions sounds dumb. I always confused with ngOnInit() and ngAfterContentInit() lifecycle hooks. On the official docs, it says:
ngOnInit() : Initialize the directive/component after Angular first displays the data-bound properties and sets the directive/component's input properties.
ngAfterContentInit(): Respond after Angular projects external content into the component's view / the view that a directive is in.
My questions are:
Q1-For ngOnInit(), what does Initialize the directive/component after Angular first displays the data-bound properties mean? Does "Initialize " means create an instance of directive/component?
Q2-For ngAfterContentInit(), what's component's view means? does the view mean the associated template html in the component's templateUrl?
Q1: No, the creation of a class instance is the method constructor which happened before ngOnInit(), a component is a directive with a template data-bound properties, view nodes etc.. and ngOnInit() is called after data-bound properties is ready, and as you may known, ngAfterViewInit() is called after view ready.
Q2: I have one example for what the "content" mean:
You define a component selector inside app.component.html with a text inside :
<custom-component>
Some random text
</custom-component>
Now inside custom-component.component.hml you can display the text "Some random text" using <ng-content></ng-content> which act as a placeholder for the text you passed down
<ng-content></ng-content>
ngAfterContentInit() simply mean the passing of "Some random text" into custom-component.component.hml view is completed.
A1) First you need to know what data-bound properties is. This answer question should help you:
What is data-bound properties?
What creates first is the constructor() The constructor comes before the ngOnInit()
https://angular.io/guide/lifecycle-hooks
A2) Yes, the view is either the xxx.component.html or the template inside of the component.ts file
https://dev.to/devpato/displaying-data-in-angular-unofficial-docs-4nd4
What is the difference between ngAfterContentInit and ngAfterViewInit?
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
The UI Router manages states for AngularJS applications and supports nested views as well as multiple named views for the same state.
Multiple named views are used like this:
<body>
<div ui-view="viewA"></div>
<div ui-view="viewB"></div>
</body>
You can also pass URL-parameters into states when navigating between states via ui-sref (Check this question: Angular ui-router - how to access parameters in nested, named view, passed from the parent template?).
Q: Is it possible to pass parameters to a named view using ui-view which then is propagated to the according state?
Q: How do i pass parameters if i switch between states by using $state.go(newState)?
A:
$state.go(newState, { Param: 123 });
The $state.go(newState, { Param: 123 }) suggested in the comments is definitely valid.
I tried using another method and it worked as well.In the main app.js file where I have defined my states, I defined a variable var myData={}; outside the module definition(but in the JS file) . Think of this as a global data variable of sorts.
In the controller for viewA you can set a variable by setting
myData.somevalue=$scope.valueFromViewA;
You can access this value in viewB by something like
$scope.valueInB=myData.somevalue
As I said, this is one way of doing it, services is another and the methods in the comment are valid too.
I have a template that includes a component.
// pods/workgroup/template.hbs
...
{{workgroup/member-add
wgId=model.id
store=store
peekUser2Workgroup=peekUser2Workgroup
}}
...
Within that component I need to lookup if something is already present in the store.
//somewhere in components/workgroup/member-add/componsent.js
let alreadyInStore = this.store.peekRecord('user2workgroup',u2wId);
I made it work by injecting the store into the component (as above), which of course is bad practise.
So I tried making a property in my parent-controller that does the store lookup:
//in components/workgroup/member-add/componsent.js
let alreadyInStore = this.get('controller').peekUser2Workgroup(u2wId);
//in pods/workgroup/controller.js
peekUser2Workgroup: function(u2wId) {
console.log(this);
console.log(this.store);
return this.store.peekRecord('user2workgroup',u2wId);
}
This works fine as long as I pass the complete store into the compentent as above.
However, if I don't pass the store to the component it get's undefined, although never accessed from the component directly (the store is present in the controller alone).
Logging into console of this gives me surprisingly the component, not the controller, this.store is undefined.
So I've learned, that with this I don't access the controller itself when a function/parameter gets called from outside/a component.
The question is, how can I make the controller to reference to itself with this?
Or how can I access the store when calling a parameter from outside?
Do I really need to pass the controller itself to himself??
like so:
// in component
let alreadyInStore = this.get('controller').peekUser2Workgroup(this.get('controller'), u2wgId);
//in controller
peekUser2Workgroup: function(myself, u2wId) {
console.log(this);
console.log(this.store);
return myself.store.peekRecord('user2workgroup',u2wId);
}
That seems very odd to me, and looks like I'm shifting around even more than I did initially when simply injecting the store to the controller...
Ember: 2.0.1
Ember-Data: 2.0.0
Instead of passing the store into the component as a property, inject it using Ember.service like this:
store: Ember.service.inject()
Then instead of passing in the function, just pass in the id vale you're looking up:
{{workgroup/member-add
wgId=model.id
}}
Now in your component you can fetch the record:
workgroup: function(){
return this.get('store').peekRecord('user2workgroup', this.get('wgId'));
}.property()
What's the best way to load a ko component with JavaScript code instead of defining a custom element in html? I tried with ko.components.defaultLoader.load but my component constructor does not hit.
I double checked and the component appears to be registered.
I believe what you are looking for is function ko.components.get(componentName, callback). What this method does is ask the component loaders to resolve the component name until it finds one. If it doesn't find one, it will call callback(null). If it does fine one, it will call callback(componentDefinition), where componentDefinition is the object used to register the component, like { viewmodel: ..., template: ...}.
As far as I can tell, there isn't a ready made function which returns a "working" component. What you have to do after getting the componentDefinition object is something like:
convert the template into a DOM element
instantiate the viewmodel (if defined)
bind the viewmodel to the DOM element
Note that this is not straight away because templates and view models can be defined in several ways.
I recommend looking at https://github.com/knockout/knockout/blob/master/src/components/componentBinding.js and see how it's done here (from line 38).
I hope this works for you, otherwise you could consider other options, like dynamically creating a div element in code with a component binding where the component name and parameters are bound to properties of a view model. Then bind this view model to the div element you just created. This should work "code only" which much less code than the other route.