icon inside button does not trigger attached function on React - html

I am building app on React. I have a table of item list and have difficult invoking function on icon.
deleteItem = event => {
this.props.deleteRecord(event);
};
const RecordList = records.map(({ category, task, duration, id }, i) => (
<tr className="record-item" key={i} id={id}>
<td>
<span className="recordItem">{category}</span>
</td>
<td>
<span>{task}</span>
</td>
<td className="time-trashIcon-container">
<span>{duration}</span>
<button
type="button"
className="trashIcon"
id={id}
onClick={this.deleteItem}
>
<i className="far fa-trash-alt" />
</button>
</td>
</tr>
));
What I want to achieve
when user clicks the trash button (icon inside button tag), it calls a function to delete item.
Problem
For now, only when I click button padding, not icon itself triggers delete function. Clicking icon does not trigger anything.
What I tried
I wrap the icon inside span and tried giving delete function as onClick eventListener. It would trigger a function but it fails to find property I want to pass id of each item which I need to delete the target item.
I don't want to use jQuery. I have tried data-x to pass property and did not work either. Any help would be appreciated.
Thank you tons in advance.

Put it inside button. using below syntax you need not to bind if you are using ES6
onClick={e => this.deleteItem(id, e)}
write your delete code inside.
deleteItem(id, event) {
//TO-DO delete code
}
Instead of using button you can use <a>
<a className="trashIcon"
id={id}
onClick={e => this.deleteItem(id, e)}/> <i className="far fa-trash-alt"/></a>

Answering my own question for anyone who might have a similar problem :)
After trying a few things out below...
<a id={id} onClick={this.delete}>
<button id={id} onClick={this.delete}><a id={id} onClick={this.delete}><i className='trashIcon'></a></button>
<button id={id} onClick={this.delete}><span id={id} onClick={this.delete}><i className='trashIcon'></span></button>
All of them invoke delete function when clicking padding of icon, not the icon itself.
The working code was just to put <span><i/><span>

Related

I want a input which has a button besides it

I want a input which has a button besides it, and whenever I click on the button it takes me to a location(to be precise : "https://localhost:5000/message/to={{inputbyuser}}") where {{inputbyuser}} is the input which the user has entered. Also as I will be hosting it later I want not the localhost to come but the webpage to get it's own domain. Is there a way?
My HTML snippet:
<input type="text" placeholder="Enter the username to chat : " class="input-required"/><button type="submit" class="btn btn-lg"><i class="fas fa-paper-plane"></i></button>
And yes the send button is a icon.
Yes!
First, give the button an ID of submit_btn and the input field an ID of input_field, then, add some JavaScript on the end of your page:
document.getElementById("submit_btn").addEventListener("click", () => {
const input_value = document.getElementById("input_field").value;
window.location.href = `https://localhost:5000/message/to=${input_value}`;
});
I hope this helped!

Trying to get an overlay to toggle on a repeating element. Can't use getElementByID

As per the title I want an overlay to trigger when an image is clicked on, but I then want it to disappear if anywhere other than 3 buttons on the overlay are clicked.
Unfortunately using getElementbyID won't work as the items repeat on a masonry layout.
<Masonry
breakpointCols={breakpointColumnsObj}
className="my-masonry-grid"
columnClassName="my-masonry-grid_column">
{this.state.data.map((data) => (
<div>
<div className="tilebutton" key="" style={{width:'100%',position:'relative'}} href={data.URL} >
<div className="tileoverlay" id="overlay" onClick={overlayoff} onclickout key={data.URL} style={{display:'none',width:'100%',zindex:'2',position:'absolute'}}>
<a className="button1" href={data.URL} onClick>{data.Name}</a>
<a className="button2" href={data.CompURL}>{data.Company}</a>
<a className="button3" href={'instagram.com/'+data.insta}>{data.Company}<img src="\img\Icons\instagram.svg" className='instalogo'/></a>
</div>
<img src={data.img} onClick={overlayon} style={{width:'100%'}}/>
</div>
</div>
))}
</Masonry>
)
function overlayon() {
document.getElementById("overlay").style.display = "block";
}
function overlayoff() {
document.getElementById("overlay").style.display = "none";
}
Unfortunately using the id "overlay" means if I click any version of the masonry it will trigger the overlay on the first image. Is there some way to:
a) identify the element clicked so it will be the one with the toggling overlay
b) have an "onclickout" I could apply to the overlay's buttons
this is about 5 days into my first ever web build so frankly I haven't got a clue what I am doing - any help is appreciated.
Thanks in advance.
The idioms used in React discourages you to manipulate the DOM directly, unless you are doing something special, such as animation. And thus I don't recommend "identifying the element clicked".
With that said, you can manipulate the data, and trigger a redraw accordingly, by invoking some setSate function (in the example below, I've defined a setShouldShowOverlay, that, when invoked, will result in a redraw).
What I recommend is for you to pull out the code inside this.state.data.map() into its own component, like so:
import React, { useState } from 'react';
function Data({ data }) {
const [ shouldShowOverlay, setShouldShowOverlay ] = useState(false);
return (
<div>
<div className="tilebutton" key="" style={{width:'100%',position:'relative'}} href={data.URL} >
<div className="tileoverlay" id="overlay" onClick={() => { setShouldShowOverlay(false); }} onclickout key={data.URL} style={{display:'none',width:'100%',zindex:'2',position:'absolute'}}>
<a className="button1" href={data.URL} onClick>{data.Name}</a>
<a className="button2" href={data.CompURL}>{data.Company}</a>
<a className="button3" href={'instagram.com/'+data.insta}>{data.Company}<img src="\img\Icons\instagram.svg" className='instalogo'/></a>
</div>
<img src={data.img} onClick={() => {
setShouldShowOverlay(true);
}} style={{width:'100%'}}/>
</div>
</div>
);
}
Then finally, update your Masonry code like so:
<Masonry
breakpointCols={breakpointColumnsObj}
className="my-masonry-grid"
columnClassName="my-masonry-grid_column">
{this.state.data.map((data) => (
<Data data={data} />
))}
</Masonry>

How to Pass JSON Object value From HTML Onclick function to JavaScript ? MVC

I am working on MVC trying to pass id on click button from HTML to JS my code where i am creating table in HTML is,
<tbody>
<tr ng-repeat="Survey in vm.AllSurveys">
<td>{{Survey.visitNumber}} </td>
<td>{{Survey.id}}</td>
<td>
<button id="myButton" onclick="myFunction('{{Survey.id}}');">Home</button>
</td>
</tr>
</tbody>
On click function is like,
function myFunction(id) {
console.log(id);
location.href = "http://localhost/Test?visitId="+id;
}
I have data in this format,
[{VisitNumber: "Visit_U_1", id: "107"},... So on]
But i got this error in html onclick line,
Error: [$compile:nodomevents] http://errors.angularjs.org/1.3.9/$compile/nodomevents
at https://ajax.googleapis.com/ajax/libs/angularjs/1.3.9/angular.min.js:6:416
at pre
<button id="myButton" onclick="myFunction('{{Survey.id}}');">
I tried solutions but did not get success
Hopes for your suggestions
You can use ng-click directive to pass data like below code
<button id="myButton" ng-click="myFunction(Survey.id);">Home</button>

How to control multiple (click) events inside a table?

Hello I hope the title is descriptive enough to understand my problem,
I have this HTML code. In <td> i have attached a (click) function. Inside this <td>, I have another div which also has a (click) function attached. When I click the button inside <td> both functions are triggered.
But, I would like only the (click) in div to be triggered when I click it and not the <td> (click).
Is it possible to happen?
<td mat-cell align="center" *ngFor="let option of options; let opt_indx = index"
(click)="optionsClicked(opt_indx, i);" id="defaultBadge-wrapper">
<div *ngIf="!rowCommands[i].defaultSelected[opt_indx]" class="defaultBadge">
<a class="badge badge-secondary" matTooltip="Click here to set this Option as Default"
(click)="markDefault(i,option.id)">Default</a>
</div>
</td>
Typescript code
markDefault(index, option: string) {
alert('this function triggered');
}
optionsClicked(option, rule) {
alert('I dont want this function to be triggered when i click markDefault');
}
In ts method pass the $event as param and include
event.stopPropagation();
or in the click event pass another function:
(click)="markDefault(i,option.id); event.stopPropagation();">Default</a>
use the stoppropagation to prevent the event from propagating
(click)="markDefault(i,option.id); event.stopPropagation();">Default</a>
just add $event.stopPropagation() to inner click.
<div *ngIf="!rowCommands[i].defaultSelected[opt_indx]" class="defaultBadge">
<a class="badge badge-secondary" matTooltip="Click here to set this Option as Default"
(click)="$event.stopPropagation();markDefault(i,option.id)">Default</a>
</div>

AngularJS change attribute values

I have rows in table which generate buttons dynamically
<tr ng-repeat="task in task">
<td>{{task.Name}}</td>
<td>{{task.Comments}}</td>
<td>{{task.Project}}</td>
<td>{{task.Duration}}</td>
<td>
<button class={{editable}} ng-click="editTask(task.id)"></button>
<button class="glyphicon glyphicon-trash"></button>
</td>
</tr>
In my Angular code I have
$scope.editTask = function(id){
if($scope.editable == "glyphicon glyphicon-edit"){
$scope.editable="glyphicon glyphicon-floppy-save";
}
else{
$scope.editable="glyphicon glyphicon-edit"
}
}
So basically I want to change the edit glyphicon to save glyphicon and the save glyphicon back to edit glyphicon. But since I have assigned class to the button it changes the glyphicons of all buttons in the table. How can I change the icon of only the button of which is clicked?
By assigning the editable variable to the task object:
$scope.editTask = function(task){
if(task.editable == "glyphicon glyphicon-trash")
task.editable="glyphicon glyphicon-floppy-save";
else
task.editable="glyphicon glyphicon-trash";
}
and in your HTML:
<button ng-class="editable" ng-click="editTask(task)"></button>
This way, you'll end up having an unique class for each of your task object.
Also, remember to use ng-class instead of the plain class attribute.
Approach 1
You can update your HTML to
<td>
<button class="glyphicon" ng-class="task.editable" ng-click="editTask(task)"></button>
<button class="glyphicon glyphicon-trash"></button>
</td>
Passing the task instead of the id directly allows you to update it's editable state directly on the task. Your controller should update the editable property
$scope.editTask = function(task){
if(task.editable == "glyphicon-edit") {
task.editable="glyphicon-floppy-save";
}
else{
task.editable="glyphicon-edit"
}
}
Note: I've passed the glyphicon class directly to the button since it won't change.
Approach 2
You could also approach it another way and keep the condition in the HTML
<button class="glyphicon" ng-class="task.editable ? 'glyphicon-edit': 'glyphicon-floppy-save'" ng-click="editTask(task)"></button>
And your controller could just update the editable property
$scope.editTask = function(task){
task.editable = !task.editable;
}
Set the editable property on the task itself and then use task.editable. This will be a unique property for each task
you need to make some changes to your code. I'm gonna provide you the code I used in order to achieve what I believe is your goal, and will then explain the reasoning behind it.
<table>
<tr ng-repeat="task in tasks">
<td>{{task.Name}}</td>
<td>{{task.Comments}}</td>
<td>{{task.Project}}</td>
<td>{{task.Duration}}</td>
<td>
<button class={{task.editable}} ng-click="editTask($index)"></button>
<button class="glyphicon glyphicon-trash"></button>
</td>
</tr>
</table>
As you can see, I included an attribute inside the task called editable. I'll be using this attribute to change the class. You'll also notice I', using $index. This is a default counter for ng-repeat.
$scope.tasks.push({Name: 'Jorge', Comments: 'Comentario',Project: 'Tengu', Duration: 45, editable: "glyphicon glyphicon-trash"});
$scope.tasks.push({Name: 'Mermelada', Comments: 'Comentario2',Project: 'DM-300', Duration: 30, editable: "glyphicon glyphicon-trash"});
You'll need to add the editable properties to your objects.
$scope.editTask = function(id){
if($scope.tasks[id].editable == "glyphicon glyphicon-trash"){
$scope.tasks[id].editable="glyphicon glyphicon-floppy-save";
} else{
$scope.tasks[id].editable="glyphicon glyphicon-trash"
}
}
I don't believe this needs much explanation. Please let me know otherwise.
If you simply want to switch between class just use ng-class
exemple, you have a variable leftOrRight, we will assume that you have two class in you css file: floatLeft and floatRight (with the attribute float: right/left; )
ng-class="{ floatRight : leftOrRight == 'right', floatLeft : leftOrRight == 'left' }"
If you set leftOrRight to "right" you will have the same thing as class="floatRight" for exemple.