I have the following attribute directive
import { Directive,HostListener,Input } from '#angular/core';
#Directive({
selector: `[appConfirmaction]`
})
export class ConfirmactionDirective {
#Input() appConfirmaction = () => {};
#Input() confirmMessage = 'Do you want to keep going?';
#HostListener('click', ['$event'])
confirmFirst() {
const confirmed = window.confirm(this.confirmMessage);
if(confirmed) {
this.appConfirmaction();
}
}
}
Then I'm using the above directive attribute in a button, such as
<button md-icon-button [appConfirmaction]="showSimpleMessage" >
The code of the function of the component is:
showSimpleMessage(){
alert("Hello");
}
This code works perfectly.
Now, suppose that I want to add a parameter to the function showSimpleMessage, such as
showSimpleMessage(name:string){
alert("Hello "+name);
}
What are the changes that I have to do to the attribute directive to support the new parameter without using a new #Input for the name parameter?
Also, Is this the proper way to call a function from an attribute directive with Angular4?
Cheers.
Use bind
<button [appConfirmaction]="showSimpleMessage.bind(null, 'Julia')" >
click me
</button>
You wouldn't have to change much. Just put argument to your calling of showSimpleMessage function in directive:
if(confirmed) {
this.appConfirmaction('some name');
}
If this doesn't work correctly you can use call() method on that function. This solution is if you want to call it from directive:
if(confirmed) {
this.appConfirmaction.call(null, 'some name');
}
First argument null is actually context this that you can provide to the function.
'some name' is the parameter of the function.
The other solution is to use bind() as suggested by #Julia
Related
The refreshTable() function is in the parent component. I need to trigger it whenever I updated information in my modal and closes it.
I am using #ng-bootstrap for my modal
For may parent.component.ts
import { NgbModal } from '#ng-bootstrap/ng-bootstrap';
constructor(
private ngbModal: NgbModal,
)
viewModal() {
const openModal = this.ngbModal.open(ModalComponent);
openModal .componentInstance.id = row.id;
}
refreshTable() {
//refresh code block here
}
For my modal.component.ts
import { NgbActiveModal} from '#ng-bootstrap/ng-bootstrap';
constructor(
private activeModal: NgbActiveModal,
)
updateParent() {
//update data to database code here
this.activeModal.close();
}
How to trigger refreshTable() from ModalComponent after closing the modal? Since there are changes in the data from database, data from parent is not updated accordingly when modal is closed.
Try to change to this
const openModal = this.ngbModal.open(ModalComponent);
openModal.componentInstance.id = row.id;
openModal.dismissed.subscribe(
_ => {
this.refreshTable();
}
)
in parent.component.ts
Pass it from the parent component to the child component as a prop.
Use bind or an arrow function to preserve the this value.
Add an output event to your modal component
#Output() onCLose: EventEmitter<any> = new EventEmitter();
When the user clicks close just call the emit() method
this.onCLose.emit(value); //value can be whatever you want to pass to the parent
Update your viewModal method in the parent to include a subscription to the close event
viewModal() {
const openModal = this.ngbModal.open(ModalComponent);
openModal.componentInstance.id = row.id;
openModal.componentInstance.onClose.subscribe(value =>
// handle the close event
this.refreshTable();
})
}
You could also do it any other way communication between components can be achieved:
service
state management (ngrx, etc)
ngBootstrap modals have a beforeDismiss event, to which you can add logic before you close the modal. You have to return a truthy value for the modal to actually close.
You could do it like this:
const openModal = this.ngbModal.open(ModalComponent, { beforeDismiss: () => this.updateParent() }); // if modal is not closing, your function is returning false.
Check here for info on that function (do use ctrl F to find the option if needeD)
Edit: #tom-fong's answer is also a good solution, but you'd have to check if you're using version > 8.0.0
I have seen examples of passing a function from a parent lit-element to a child one like here - https://medium.com/#westbrook/litelement-to-do-app-1e08a31707a4
But I want the users of my element, not to be forced to create a wrapper element to use my element.
For example, my element is a dialog that computes some value.
I was hoping I could do something like this (html using my element):
<script>
function latLongResult(lat,long)
{
console.log("resulting lat long called");
}
</script>
<lat-long-chooser id="latLongDialog" resultingLatLong=${latLongResult(lat,long)}></lat-long-chooser>
And then in my element:
export class LatLongChooser extends LitElement {
static get properties() {
return {
latDecimalDegrees: Number,
longDecimalDegrees: Number,
resultingLatLong: {
type: Function,
}
};
}
saveConvertedValues() {
console.log("save other values called");
this.resultingLatLong(this.latDecimalDegrees,this.longDecimalDegrees)
}
When I try this, I get JavaScript errors.
Your element's code is fine, the way you're trying to set the function is what's a bit off.
You see, the syntax you're using would work if you were in a lit-html/lit-element render function (just with a few corrections, it would be .resultingLatLong=${latLongResult})
However, since you're in a script at the main level you should do something like this:
<script>
function latLongResult(lat,long){
console.log("resulting lat long called");
}
// do it like this so that it's set as a property, setting it as an attribute would require some rather complicated extra code
document.querySelector('#latLongDialog').resultingLatLong = latLongResult;
</script>
<lat-long-chooser id="latLongDialog"></lat-long-chooser>
Here's a glitch with a minimal example of something similar in action
You can also configure a observed attributes, in your property resultingLatLong in your lat-long-chooser and set the attribute: false like that:
static get properties() {
return {
latDecimalDegrees: Number,
longDecimalDegrees: Number,
resultingLatLong: {
type: Function,
attribute: false
}
};
}
This will prevent an observed attribute from being created for a property.
Since you've access to the window object inside your components another way to do this would be to pass the name of the function and access the function itself via window[functionName]:
customElements.define('my-example', class extends LitElement {
static properties = {
greet: {}
}
_greet() {
window[this.greet]('Hello World!');
}
render() {
return html`
<button #click=${this._greet}>Greet</button>
`;
}
});
Then in your page:
<body>
<my-example greet="greetHandler"></my-example>
<script>
function greetHandler(msg) {
alert(msg);
}
</script>
</body>
I have an AngularJS 1.5 component that takes an optional callback function as an attribute binding. I would like to determine whether that attribute is included.
<silly-button></silly-button> <!-- Don't Click Me! -->
<silly-button on-silly-click="handleClick()"></silly-button> <!-- Click Me! -->
Given the trivial example below, how can I implement the the onClickIsNotProvided() function?
angular
.module('example')
.component('sillyButton')
.bindings({
onSillyClick: '&'
})
.controller(['$scope', ($scope) => {
$scope.onClickIsNotProvided = () => {
// this.onSillyClick is always defined, so return value is always false :(
return !this.onSillyClick;
};
}])
.template(`
<button ng-click="$ctrl.onSillyClick()">
<span ng-if="onClickIsNotProvided()">Don't</span>
Click Me!
</button>
`);
You could use &? same as =?, #? to mark whether that parameter is optional or not.
Some reference can be found in here. Although it does not specifically talk about optional function bindings.
I think this is the function that you would have to add:
function onClickIsNotProvided(item) {
var elementAttributeValue = item.attributes['on-silly-click'].value;
if (!elementAttributeValue) {
return true;
}
else {
return false;
}
This would go into the same place as your other angular for the controller.
Is there any way to write a code like that in angular 2?
var closeButton1 = document.querySelector('.close1');
var close1ClickStream = Rx.Observable.fromEvent(closeButton1, 'click');
I have tried many ways to put them in angular 2 component put it does not worked well!
I tried something like this
component.ts
#ViewChild('delete') closeButton1: ElementRef;
close1ClickStream = Observable.fromEvent(closeButton1, 'click');
component.html
<!-- this code is inside *ngFor -->
<li><a #delete [routerLink]="['/update', item.id]">delete</a></li>
The problem is that I can not access the element even if I used AfterContentInit. Moreover, if I could access it, can I use the Observable.fromEvent(...)?
Use directives to handle events
#Directive({
selector: '[click-handler]'
})
export class ClickHandler {
constructor(public elementRef: ElementRef,) {
}
#HostListener('click', ['$event'])
onClick(e) {
// do staff here
}
}
usage
<button click-handler> click </button>
Anyway if you want to do it using Observables you will need
elementRef.nativeElement which is available here , just implement OnInit method and you are good to go.
Yes you can do it :
import { Observable } from 'rxjs/Observable';
//...
#ViewChild('delete') closeButton1: ElementRef;
close1ClickStream = Observable.fromEvent(closeButton1, 'click');
i have the following code which extends the JQuery and adds a method to the JQuery:
$.fn.attachWithMessage = function () {
$(this).focusin(showMessage());
}
function showMessage() {
alert('hi');
}
so I can use that code as follows :
<input type="text" name="name" id="textbox" />
$(document).ready(function () {
$("#textbox").attachWithMessage ();
});
when I load the page for the first time, a message box shows up with ('hi') message.
even if I didn't click in the text box.
I also tried the click event, and the message still shows automatically.
any ideas ??
The issue here is that when you pass showMessage() as a parameter to focusin, the function showMessage is executed and the return value is passed to focusin.
Instead you need to pass a reference to the function (without the paranthesis).
Use the following code to extend:
$.fn.attachWithMessage = function () {
$(this).focusin(showMessage);
}
Working example# http://jsfiddle.net/eXEP5/
EDIT:
If you want to pass a parameter to showMessage then try this:
$.fn.attachWithMessage = function () {
var param1 = "Some Param";
$(this).focusin(function(){
showMessage(param1); //Make sure showMessage is modified accordingly for the parameters.
});
}
just remove the parenthesis
$(this).focusin(showMessage());
should be
$(this).focusin(showMessage);
Hope this helps