I have this code
var html = [];
for (var i = 0, len = this.props.tables.length; i < len; i++) {
var id = this.props.tables[i]._id;//._str;
html.push(
<div key={id} className="col-xs-6 col-md-3">
<div className={"thumbnail " + cls}>
<div>
<a role="button" className="btn btn-danger glyphicon glyphicon-trash"
onClick={() => { this.deleteTable(id) } } />
</div>
</div>
</div>);
}
which renders a list of "tables", and I am calling a function that removed the data given the id. However, mt ID I am passing ends up deleting a different "table" (the last one, always) so clearly I need to somehow save the id with the delete button somehow. How do I do that?
(I used to pass this.props.tables[i]._id but it told me that this.props.tables[i] is undefined because it was looking at the latest i),
This is React with Meteor.
I got around it by creating a new class TableDelete and passing the ID as a param.
So instead of the <a\> I have
<TableDelete key="del" params={this.props.tables[i]._id} />
where TableDelete is basically
/**
* Delete a row from the Tables collection, given its id
* #param id the id of the column
*/
deleteTable(id) {
Meteor.call('tables.removeTable', id);
}
/**
* Display the delete button based on the parameters
*/
render() {
// set the callback depending on the type of delete (row/col)
var callback = this.deleteTable; //row
var title = 'Delete Table';
// display the button
return (
<a role="button" data-toggle="tooltip" title={title}
className={'btn btn-danger glyphicon glyphicon-trash'}
onClick={() => { callback(this.props.params); } } >
</a>
);
}
and the params are
/**
* params: parameters to callback function
*/
TableDelete.propTypes = {
params: PropTypes.object.isRequired
};
I still do not know why this would work but the thing above wouldn't...
Related
I'm making a task board project.
Must say I'm using only HTML, CSS, JS, and nothing else right now.
I'm making a fade-in effect to the newly added note (ul element), and I would like to delete the fade-in class from the previously added note.
this is a chunk of my code that displays the note inside the div.
function displayAllTasks(allTasks){
taskNotesDiv.innerHTML = "";
for(const task of allTasks){
const index = allTasks.indexOf(task);
const note = `
<div class"noteDiv">
<ul class="fadeInNote">
<button type="button" onclick="deleteTask(${index})">
<i class="fa-solid fa-trash deleteButton"></i>
</button>
<li>Task: ${task.task}</li>
<li>Description: ${task.textArea}</li>
<li>Date: ${task.date}</li>
<li>Time: ${task.time}</li>
</ul>
</div>
`
taskNotesDiv.innerHTML += note;
}
}
I tried already another function to delete it but with no success.
any help would be appreciated!
There can be multiple approaches, but my approach is to create element using document.createElement . The modified JS will become:
function displayAllTasks(allTasks) {
last_ul = null; // store the last ul element added
taskNotesDiv.innerHTML = "";
for (const task of allTasks) {
const index = allTasks.indexOf(task);
let noteDiv = document.createElement('div');
noteDiv.classList.add('noteDiv');
note_ul = document.createElement('ul');
note_ul.classList.add('fadeInNote');
note_ul.innerHTML = `
<button type="button" onclick="deleteTask(${index})">
<i class="fa-solid fa-trash deleteButton"></i>
</button>
<li>Task: ${task.task}</li>
<li>Description: ${task.textArea}</li>
<li>Date: ${task.date}</li>
<li>Time: ${task.time}</li>`
noteDiv.appendChild(note_ul);
// if it is not the first element, then remove the class from previous
if (last_ul != null) {
last_ul.classList.remove('fadeInNote');
}
last_ul = note_ul; // this becomes previous for next iteration
taskNotesDiv.appendChild(noteDiv);
}
// remove class of the last element
if (last_ul != null) {
last_ul.classList.remove('fadeInNote');
}
}
In my application I have saved the data when we click on it(we can add the multiple data by entering some data and save the multiple data by clicking the save button).
.component.html
<ng-container *ngFor="let categoryDetail of selectedCategoryDetails">
<div class="__header">
<div>
<b>{{ categoryDetail.category }}</b>
</div>
</div>
<div
class="clinical-note__category__details"
*ngIf="categoryDetail.showDetails">
<ul>
<li class="habit-list"
*ngFor="let habits of categoryDetail.habitDetails" >
<div class="target-details">
<b>{{ clinicalNoteLabels.target }}: </b
><span class="habit-list__value">{{ habits.target }}</span>
</div>
</li>
</ul>
<div class="habit-footer">
<span class="m-l-10"
[popoverOnHover]="false"
type="button"
[popover]="customHabitPopovers"><i class="fa fa-trash-o" ></i> Delete</span>
</div>
<div class="clinical-note__popoverdelete">
<popover-content #customHabitPopovers [closeOnClickOutside]="true">
<h5>Do you want to delete this habit?</h5>
<button
class="btn-primary clinical-note__save" (click)="deletedata(habits);customHabitPopovers.hide()">yes </button>
</popover-content></div>
</div>
</ng-container>
In the above code when we click on delete button it will show some popup having buttons yes(implemented in above code) and now so my requirement is when we clcik on yes button in from the popover it has to delete the particular one.
.component.ts
public saveHealthyHabits() {
let isCategoryExist = false;
let categoryDetails = {
category: this.clinicalNoteForm.controls.category.value,
habitDetails: this.healthyHabits.value,
showDetails: true,
};
if (this.customHabitList.length) {
categoryDetails.habitDetails = categoryDetails.habitDetails.concat(
this.customHabitList
);
this.customHabitList = [];
}
if (this.selectedCategoryDetails) {
this.selectedCategoryDetails.forEach((selectedCategory) => {
if (selectedCategory.category === categoryDetails.category) {
isCategoryExist = true;
selectedCategory.habitDetails = selectedCategory.habitDetails.concat(
categoryDetails.habitDetails
);
}
});
}
if (!this.selectedCategoryDetails || !isCategoryExist) {
this.selectedCategoryDetails.push(categoryDetails);
}
this.clinicalNoteForm.patchValue({
category: null,
});
this.healthyHabits.clear();
public deletedata(habits){
if (this.selectedCategoryDetails) {
this.selectedCategoryDetails.forEach((selectedCategory) => {
if (selectedCategory.category ==categoryDetails.category) {
isCategoryExist = true;
this.selectedCategoryDetails.splice(habits, 1);
}
});
}
}
The above code I have written is for saving the data(we can enter multiple data and save multiple )
Like the above I have to delete the particular one when we click on yes button from the popover.
Can anyone help me on the same
If you're iterating in your html like:
<... *ngFor="let categoryDetails of selectedCategoryDetails" ...>
and your button with deletedata() is in the scope of ngFor, you can:
Change your iteration to include index of an item and trackBy function for updating the array in view:
<... *ngFor="let categoryDetails of selectedCategoryDetails; let i = index; trackBy: trackByFn" ...>
On the button click pass the index to deletedata() method like:
deletedata(index)
Create your deletedata method like:
deletedata(index:number){
this.selectedCategoryDetails.splice(index, 1);
// other code here, like calling api
// to update the selectedCategoryDetails source
// etc.
}
Create trackByFn method like:
trackByFn(index,item){
return index;
}
EDIT: Without index
If you want to iterate over selectedCategoryDetails in the ts file, without using ngFor with index in your html, you can have your deletedata like this:
deletedata(categoryDetails:any){
for (let i = this.selectedCategoryDetails.length - 1; i >= 0; i--) {
if (this.selectedCategoryDetails[i] === categoryDetails.category) {
this.selectedCategoryDetails.splice(i, 1);
}
}
}
It will iterate over selectedCategoryDetails backwards and remove the categoryDetails if it finds it in the array of objects.
Now, you only need to pass the categoryDetails to deletedata in your html:
(click)="deletedata(categoryDetails);customHabitPopovers.hide()"
I have two files. A list Component and a Single Item Component. In my app, the user can select multiples items. Then I create an state element in "list" "items" and my idea is that when the user make click on the item button, the list element notify to List Component and save the item in Items array from "list".
I have the next code
List.jsx:
registrarItems(data,item){
console.log(data,"aqui 1 con",item);
let items = this.state.itemsAgregados.slice();
if(!items.indexOf(data.id_producto)){
console.log("no se encuentra");
items.push(id);
this.setState({
'itemsAgregados':items
});
}else{
console.log("ya existe");
item.removerSeleccion();
}
console.log("registrando items",id);
}
render() {
return (
<div className="content-app">
<Navbar data={this.menu}/>
<div className="container lista-productos">
{
this.state.productos.map((producto, index) => {
return (
<Item data={producto}
registro = {this.registrarItems}
key={producto.id_producto}/>
);
})
}
</div>
</div>
);
}
And Item.jsx:
render() {
let props = this.props;
let img = JSON.parse(props.data.imagen);
let imgPath = Rutas.apiStatic + 'img/productos/' + props.data.id_producto + '/' + img.sm;
props.data.items = this;
return (
<div className="row item-listado">
<div className="col-xs-3">
<img src={imgPath} className="img-circle img-item"/>
</div>
<div className="col-xs-7">
<Link to={Rutas.producto + props.data.identificador}>
<h3 className="titulo">{props.data.titulo}</h3>
<span className="price">$ {props.data.precio}</span>
</Link>
</div>
<div className="col-xs-2 text-right">
<ul className="list-unstyled list-acciones">
<li>
<a href="#" onClick={()=>props.registro(props.data,this)} className={this.state.classAdd}>
<i className="fa fa-plus"></i>
</a>
</li>
</ul>
</div>
</div>
)
}
As you can see, I pass the "registrarItems" method as a param to Item and there, i add this as onClick event in the tag from item. But I need pass the "data" and the own "item" element to the onclick function. The first, for save the element clicked in the Items array, or remove it (if it already exists) because the button may have a toggle function. But in my "console.log" both params passed on the onClick method with the arrow function shows as "undefined".
I saw some examples and i don't get my error. can anybody helpme? thanks.
The final solve for this was simple. I resolved it with something similar as Free-soul said on his comment.
First, I passed the List Component as a param to item. Below my code in List's render method:
{
this.state.productos.map((producto, index) => {
this.items[producto.id_producto] = producto;
return (
<Item data={producto}
parent = {this}
key={producto.id_producto}/>
);
})
}
Then I get the parent param in componentDidMount method and later I call the validarItem function directly from the List method and I pass the params that i need.
Here my Item code:
onClickPlus(id,data) {
//{Rutas.listas + 'productos/' + props.data.id_producto //Url para pasar uno solo
this.setState({
classAdd:'selected'
})
if(!this.state.parent.validarItem(this.state.data)){
this.removerSeleccion()
}
if(this.state.seleccionMultiple){
}
}
removerSeleccion(){
this.setState({classAdd:'normal'})
}
componentDidMount(){
this.setState({
parent: this.props.parent,
data : this.props.data
})
}
render() {
return (
// more code
<a href="#" onClick={() => this.onClickPlus(parent)} className={this.state.classAdd}>
<i className="fa fa-plus"></i>
</a>
//more render code...
)
}
I don't know if this is the best practice, but works for me.
This is my HTML(list of people)
<button class="btn btn-primary btn-block" id="add_user">Add new user</button>
<ul id="users_list" contenteditable="true">
<li class="user_data">
<img src="http://img.dunyanews.tv/blog_user_images/anchors//15_user_icon.png" alt="44user" class="user_image" />
<div class="user_data_id text-left">Id:></div>
<div class="user_data_username text-left">Username:</div>
<div class="user_data_firstname text-left">Firstname:</div>
<div class="user_data_lastname text-left">Lastname:</div>
<button class="btn btn-danger delete_user">X</button>
</li>
</ul>
This is my Javascript (one function for adding and one for deleting). First work well, but second (deleting) - delete only first (or [0]) element
var addUser = document.getElementById('add_user'),
usersList = document.getElementById('users_list'),
userTemplate = document.getElementsByClassName('user_data');
deleteUser = document.getElementsByClassName('delete_user');
//Function for adding elements
addUser.addEventListener('click', (function() {
var newUser = userTemplate[0].cloneNode(true);
usersList.appendChild(newUser);
}));
//Function for deleting element
for (i = 0; i < deleteUser.length; i++) {
(function(e) {
deleteUser[e].addEventListener('click', (function() {
usersList.removeChild(userTemplate[e]);
}));
})(i);
}
Try this code:
I changed the display on the default template to hidden so we will also have one user to clone from. Otherwise, the user can delete all and we have nothing to clone from.
<button class="btn btn-primary btn-block" id="add_user">Add new user</button>
<ul id="users_list" contenteditable="true">
<--! This display none is important -->
<li class="user_data" style="display: none;">
<img src="http://img.dunyanews.tv/blog_user_images/anchors//15_user_icon.png" alt="44user" class="user_image" />
<div class="user_data_id text-left">Id:></div>
<div class="user_data_username text-left">Username:</div>
<div class="user_data_firstname text-left">Firstname:</div>
<div class="user_data_lastname text-left">Lastname:</div>
<button class="btn btn-danger delete_user">X</button>
</li>
</ul>
To make sure we are deleting the correct user, I added an array of names for testing.
var names = ['Noah', 'Sophia', 'Liam', 'Emma', 'Jacob', 'Olivia', 'Mason', 'Isabella', 'William', 'Ava', 'Ethan', 'Mia', 'Michael', 'Emily', 'Alexander', 'Abigail', 'Jayden', 'Madison', 'Daniel', 'Elizabeth'];
var addUser = document.getElementById('add_user'),
usersList = document.getElementById('users_list'),
userTemplate = document.getElementsByClassName('user_data');
deleteUser = document.getElementsByClassName('delete_user');
//Function for adding elements
addUser.addEventListener('click', (function() {
var newUser = userTemplate[0].cloneNode(true);
// add name to user so we can test.
newUser.getElementsByClassName('user_data_firstname')[0].innerHTML += ' ' + names.pop();
// make this user visible
newUser.style.display = '';
// Wire click event to remove this user.
newUser.getElementsByClassName('delete_user')[0].addEventListener('click', (function() {
usersList.removeChild(newUser);
}));
usersList.appendChild(newUser);
}));
// Add one user
addUser.click();
Note: You start with one user and you loop through the user list to add the remove, so when new users are added, the click to remove event is not wired.
I removed the loop and wire it as we add a new user.
Obviously our code will fail if we click on add users and we run out of names, but that's enough for our test.
I have added a server side pagination with table sorter successfully. I just would like to know how can I refresh it? I would like to create a button to call a refresh function. Does anyone know if there is any method to do it? I do not want to reload the page for it.
UPDATE:
ajaxProcessing: function(data){
if (data && data.hasOwnProperty('rows')) {
var r, row, c, d = data.rows,
total = data.total_rows,
headers = data.headers,
rows = [],
len = d.length;
for ( r=0; r < len; r++ ) {
row = []; // new row array
// cells
for (c in d[r]) {
if (typeof(c) === "string") {
row.push(d[r][c]); //add each table cell data to row array
}
}
rows.push(row); // add new row array to rows array
}
var items="";
$("#tabelaTickets tr:has(td)").remove();
if (rows!==null && rows.length!== 0) {
$.each(rows,function(index,item) {
$("#tabelaTickets").append('<tr class="danger"><td align="center" style="width: 70px"><a type="button" class="btn btn-primary btn-xs" data-placement="right" title="Visualizar ticket" data-toggle="modal" class="btn btn-primary" href="visualizar.php?ticket='+item[3]+'"> #' + item[3] + '</a></td><td><div style="text-overflow:ellipsis;overflow:hidden;width:250px">' + item[4] + '</div></td><td><div style="text-overflow:ellipsis;overflow:hidden;width:350px;">' + item[5] + '</div></td><td><div style="text-overflow:ellipsis;overflow:hidden;width:250px;">' + item[6] + '</div></td><td><div style="text-overflow:ellipsis;overflow:hidden;width:60px;">' + item[7] + '</div></td><td><div style="text-overflow:ellipsis;overflow:hidden;width:70px;">' + item[8] + '</div></td></tr>');
});
}else{
$("#tabelaTickets").append('<tr><td colspan = "6" align="center">SEM RESULTADO A SER EXIBIDO</td></tr>');
}
$("#tabelaTickets").trigger("update");
$("#tabelaTickets").trigger("appendCache");
$("#pleaseWaitDialog").modal('hide');
// in version 2.10, you can optionally return $(rows) a set of table rows within a jQuery object
return [ total];
}
},
Thanks since now,
Erik
your repsonse is JSON, it's easy with a little AJAX function.
example your HTML is look like :
<div class="wrapper">
<div class="item">
<span>item 01</span>
</div>
<div class="item">
<span>item 02</span>
</div>
<div class="item">
<span>item 03 </span>
</div>
</div>
<button class="btn refresh-btn" type="submit"></button>
your response JSON maybe look like :
response = {
{ content : item11 },
{ content : item12 },
{ content : item13 }
};
your HTML render function with AJAX will be look like :
$('.refresh-btn').on('click', function() {
var url = 'yourUrl/?param=refresh&example=true';
var $wrapper = $('.wrapper'); // a div that wrap your new HTML.
$.get(url, {}) //call AJAX GET new item.
.done(function(data) {
$wrapper.html(''); // clear old list;
var $template = $('<div/>', {class : 'item'} ); // create item's HTML.
data.arrayItemList.forEach(function(item) {
var itemTemplate = $template.clone();
itemTemplate.append($('<span/>').text(item.content));
$wrapper.append(itemTemplate); // add new item in list.
});
});
})
that's mean : you create new HTML, and fill it with your data, everything worked fine.
Some time I create a empty template some where in view and clone it.
<div class="sample-template">
<div class="item">
<span> </span>
</div>
</div>
when I need it, I call the jQuery var $template = $('.sample-template').clone(); then fill data with $template.find('span').text(item.content);