I am trying to fire click event (or any other event) on element programatically , In other word I want to know the similar features as offered by jQuery .trigger() method in angular2.
Is there any built in method to do this? ..... if not please suggest how can i do this
Consider the following code fragment
<form [ngFormModel]="imgUploadFrm"
(ngSubmit)="onSubmit(imgUploadFrm)">
<br>
<div class="input-field">
<input type="file" id="imgFile" (click)="onChange($event)" >
</div>
<button id="btnAdd" type="submit" (click)="showImageBrowseDlg()" )>Add Picture</button>
</form>
Here when user click the btnAdd it should fire the click event on imgFile
Angular4
Instead of
this.renderer.invokeElementMethod(
this.fileInput.nativeElement, 'dispatchEvent', [event]);
use
this.fileInput.nativeElement.dispatchEvent(event);
because invokeElementMethod won't be part of the renderer anymore.
Angular2
Use ViewChild with a template variable to get a reference to the file input, then use the Renderer to invoke dispatchEvent to fire the event:
import { Component, Renderer, ElementRef, ViewChild } from '#angular/core';
#Component({
...
template: `
...
<input #fileInput type="file" id="imgFile" (click)="onChange($event)" >
...`
})
class MyComponent {
#ViewChild('fileInput') fileInput:ElementRef;
constructor(private renderer:Renderer) {}
showImageBrowseDlg() {
// from http://stackoverflow.com/a/32010791/217408
let event = new MouseEvent('click', {bubbles: true});
this.renderer.invokeElementMethod(
this.fileInput.nativeElement, 'dispatchEvent', [event]);
}
}
Update
Since direct DOM access isn't discouraged anymore by the Angular team this simpler code can be used as well
this.fileInput.nativeElement.click()
See also https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/dispatchEvent
I also wanted similar functionality where I have a File Input Control with display:none and a Button control where I wanted to trigger click event of File Input Control when I click on the button, below is the code to do so
<input type="button" (click)="fileInput.click()" class="btn btn-primary" value="Add From File">
<input type="file" style="display:none;" #fileInput/>
as simple as that and it's working flawlessly...
This worked for me:
<button #loginButton ...
and inside the controller:
#ViewChild('loginButton') loginButton;
...
this.loginButton.getNativeElement().click();
To get the native reference to something like an ion-input, ry using this
#ViewChild('fileInput', { read: ElementRef }) fileInput: ElementRef;
and then
this.fileInput.nativeElement.querySelector('input').click()
Günter Zöchbauer's answer is the right one. Just consider adding the following line:
showImageBrowseDlg() {
// from http://stackoverflow.com/a/32010791/217408
let event = new MouseEvent('click', {bubbles: true});
event.stopPropagation();
this.renderer.invokeElementMethod(
this.fileInput.nativeElement, 'dispatchEvent', [event]);
}
In my case I would get a "caught RangeError: Maximum call stack size exceeded" error if not. (I have a div card firing on click and the input file inside)
If you want to imitate click on the DOM element like this:
<a (click)="showLogin($event)">login</a>
and have something like this on the page:
<li ngbDropdown>
<a ngbDropdownToggle id="login-menu">
...
</a>
</li>
your function in component.ts should be like this:
showLogin(event) {
event.stopPropagation();
document.getElementById('login-menu').click();
}
Related
Here is my code
import React from 'react'
import PropTypes from "prop-types";
export default function Button({ htmlType, type, disabled, action, ...props}) {
return (
<button type={htmlType} onClick={action}>
{props.children}
</button>
)
}
Button.propTypes = {
htmlType: PropTypes.string.isRequired,
action: PropTypes.func,
disabled: PropTypes.bool
};
I call Button component by this code
<Button disabled={true}>button title</Button>
I want to add disabled html attribute to button when disabled of props is true, how to do it ?
You could line single line if-else statements like this:
<button disabled={propsDisabled}>button title</button>
Here, propsDisabled is the variable which you can pass through the props, and it is a boolean variable which will either be true or false. I have not used disabled itself to avoid confusion but you can use the variable name as disabled.
When propsDisabled is true, the button will be dissabled, and when propsDisabled is false the button will not be disabled.
Aya, I couldn't exactly understand your question, it looks like you're trying to solve a problem, when you have a second problem in the question in the first place.
Are you using Ant components? use the disabled prop on the <Button /> component itself. (notice the capital B in the component name Button).
<Button disabled={true} />
// or (it's the same but different JSX syntax)
<Button disabled />
This is the same answer answered by the brother #Abdul Qadir.
If you're working with native HTML elements, also, you can call the disabled attribute on the <button /> element (notice the small character b in the element name button) the same way and it should work:
<button disabled={true}>I'm disabled</button>
// or (the same but different syntax)
<button disabled>I'm disabled</button>
So here are the two answers,
If you're working with Ant components:
import { Button } from 'antd';
const CustomButton = ({ disabled, children }) =>{
return <Button disabled={disabled}>{children}</Button>
}
If you're working with native HTML elements:
const CustomButton = ({ disabled, children }) =>{
return <button disabled={disabled}>{children}</button>
}
I have a form in Angular that has two buttons tags in it. One button submits the form on ng-click. The other button is purely for navigation using ng-click. However, when this second button is clicked, AngularJS is causing a page refresh which triggers a 404. I’ve dropped a breakpoint in the function and it is triggering my function. If I do any of the following, it stops:
If I remove the ng-click, the button doesn’t cause a page refresh.
If I comment out the code in the function, it doesn’t cause a page refresh.
If I change the button tag to an anchor tag (<a>) with href="", then it doesn’t cause a refresh.
The latter seems like the simplest workaround, but why is AngularJS even running any code after my function that causes the page to reload? Seems like a bug.
Here is the form:
<form class="form-horizontal" name="myProfile" ng-switch-when="profile">
<fieldset>
<div class="control-group">
<label class="control-label" for="passwordButton">Password</label>
<div class="controls">
<button id="passwordButton" class="secondaryButton" ng-click="showChangePassword()">Change</button>
</div>
</div>
<div class="buttonBar">
<button id="saveProfileButton" class="primaryButton" ng-click="saveUser()">Save</button>
</div>
</fieldset>
</form>
Here is the controller method:
$scope.showChangePassword = function() {
$scope.selectedLink = "changePassword";
};
If you have a look at the W3C specification, it would seem like the obvious thing to try is to mark your button elements with type='button' when you don't want them to submit.
The thing to note in particular is where it says
A button element with no type attribute specified represents the same thing as a button element with its type attribute set to "submit"
You can try to prevent default handler:
html:
<button ng-click="saveUser($event)">
js:
$scope.saveUser = function (event) {
event.preventDefault();
// your code
}
You should declare the attribute ng-submit={expression} in your <form> tag.
From the ngSubmit docs
http://docs.angularjs.org/api/ng.directive:ngSubmit
Enables binding angular expressions to onsubmit events.
Additionally it prevents the default action (which for form means sending the request to the server and reloading the current page).
I use directive to prevent default behaviour:
module.directive('preventDefault', function() {
return function(scope, element, attrs) {
angular.element(element).bind('click', function(event) {
event.preventDefault();
event.stopPropagation();
});
}
});
And then, in html:
<button class="secondaryButton" prevent-default>Secondary action</button>
This directive can also be used with <a> and all other tags
You can keep <button type="submit">, but must remove the attribute action="" of <form>.
I wonder why nobody proposed the possibly simplest solution:
don't use a <form>
A <whatever ng-form> does IMHO a better job and without an HTML form, there's nothing to be submitted by the browser itself. Which is exactly the right behavior when using angular.
Add action to your form.
<form action="#">
This answer may not be directly related to the question. It's just for the case when you submit the form using scripts.
According to ng-submit code
var handleFormSubmission = function(event) {
scope.$apply(function() {
controller.$commitViewValue();
controller.$setSubmitted();
});
event.preventDefault();
};
formElement[0].addEventListener('submit', handleFormSubmission);
It adds submit event listener on the form.
But submit event handler wouldn't be called when submit is initiated by calling form.submit(). In this case, ng-submit will not prevent the default action, you have to call preventDefault yourself in ng-submit handler;
To provide a reasonably definitive answer, the HTML Form Submission Algorithm item 5 states that a form only dispatches a submit event if it was not submitted by calling the submit method (which means it only dispatches a submit event if submitted by a button or other implicit method, e.g. pressing enter while focus is on an input type text element).
See Form submitted using submit() from a link cannot be caught by onsubmit handler
I also had the same problem, but gladelly I fixed this by changing the type like from type="submit" to type="button" and it worked.
First Button submits the form and second does not
<body>
<form ng-app="myApp" ng-controller="myCtrl" ng-submit="Sub()">
<div>
S:<input type="text" ng-model="v"><br>
<br>
<button>Submit</button>
//Dont Submit
<button type='button' ng-click="Dont()">Dont Submit</button>
</div>
</form>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.Sub=function()
{
alert('Inside Submit');
}
$scope.Dont=function()
{
$scope.v=0;
}
});
</script>
</body>
Just add the FormsModule in the imports array of app.module.ts file,
and add import { FormsModule } from '#angular/forms'; at the top of this file...this will work.
My parent component ts file contains this code:
openNewModal(): void {
this.$modal.show(CategoryAddModalComponent)
.subscribe(r => {
});
location.reload();
}
My child component html:
<form action="">
<label>Enter Category</label>
<input name="cate" type="text">
<input name="category" type="text">
<button class="common-btn btn-cancel" (click)="modal.hide();l>Cancel</button>
<button class="common-btn btn" type="submit" (click)="fun_addcategory()">Submit</button>
</form>
So using this openNewModal() function Im calling my child component model. Now On submit of my child component I need to reload my parent component file. If I try to call location.reload in this function, my child component is getting reloaded. But I need to reload parent component. Can somebody please guide me how to do this?
No need to Reload the page
Use ChangeDetectorRef to detect changes manually inside parent
Example:
parent.ts
import {ChangeDetectorRef} from '#angular.core';
constructor(private cdr:ChangeDetectorRef){}
ngOnInit(){
this.service.susbscribe((data)=>{
this.data=data;
//detect the change manually using
this.cdr.detectChanges();
//Checks this view and its children.
local change detection checks
})}
You need to pass an addition flag to skip location changes like this
'''
this.router.navigate(['parentComponent', id, type], {skipLocationChange: true});
'''
I have a custom event directive called enterListener defined like so
import { Directive, EventEmitter, Output, HostListener } from "#angular/core";
#Directive({
selector: '[enterListener]'
})
export class EnterKeyDirective {
#Output() emitter: EventEmitter<any> = new EventEmitter();
#HostListener('keyup', ['$event'])
onEnter($event: any) {
if ($event.key === 'Enter') {
this.emitter.emit($event);
}
}
}
And its implemented in my html like so
<input (enterListener)="search()" id="searchBar" [(ngModel)]="searchValue" class="card-img" type="text" placeholder="Search" />
What I'm trying to accomplish is basically what the (click) event listener does, if a specific thing happens, a click, execute a specific function. For my directive, if the user presses enter then execute my method called, search().
Right now on any key up I successfully break into my directive which exists in a file separate of my component file. And it successfully recognizes when the enter key is pressed.
But it won't trigger my search() function. What am I missing to make the directive recognize that an event handler is attached to it similar to how (click)="aMethod()" functions?
If you really want to use a directive, you need to bind with the name of the event emitter declared in the directive
<input [enterListener] (emitter)="search($event)" id="searchBar" [(ngModel)]="searchValue" class="card-img" type="text" placeholder="Search" />
Otherwise, as suggested, you can directly check for keyup in component's template, on input element
Try replacing your HTML to something like this
<input (keyup)="search()" id="searchBar" [(ngModel)]="searchValue" class="card-img" type="text" placeholder="Search" />
Why is this Upload File form example working in Index.html and does not work in any component.html file?
If i move it to any component.html clicking Add File does not even open the browse dialog.
<form id="upload" method="post" action="upload.php" enctype="multipart/form-data">
<div id="drop">
<a>Add File</a> Drag and Drop
<input type="file" name="upl" />
</div>
<ul id="uploadList"></ul>
</form>
Edit: I must mention that i import the js files only in Index.html, and i'm not importing also in System.js or angular-cli.build.js
In Index.html one of the references is:
<script src="assets/js/uploadScript.js"></script>
And this is the code from uploadScript.js that should open the browser dialog:
$('#drop a').click(function(){
$(this).parent().find('input').click();
});
Your code in uploadScript.js is (I guess) initialized when the DOM is ready, thats basic how JQuery initialization works. But since your component is not yet in the DOM, nothing is found.
You need to put the initialization code directly into your component, so its called at the correct time, when the form is actually rendered in DOM.
Try to change your to component something like this:
import { Component, ElementRef } from '#angular/core';
// reference to jQuery
declare var $: any;
#Component({
selector: 'my-component',
template: `
<form id="upload" method="post" action="upload.php" enctype="multipart/form-data">
<div id="drop">
<a (click)="addFile()">Add File</a> Drag and Drop
<input type="file" name="upl" />
</div>
<ul id="uploadList"></ul>
</form>
`
})
export class JQueryComponent
{
// get the ElementRef
constructor(private _elRef: ElementRef)
{
}
public addFile(): void
{
$(this._elRef.nativeElement).find('#drop a').parent().find('input').click();
}
}
The important part is to use Angular 2 (click) bound directly to the Add File anchor. ElementRef provides a reference to your html DOM element, which can be used to simulate actual click event on the input type="file"