I am programming in an Angular 2 project. I have a several component where I want to use the same dialogue confirm box. Therefore i have put the confirm code in a separate class. The dialogue box is supposed to check whether a user wants to continue or save data.
I am using Angular2-modal for this pupose.
When either button on the confirm is pressed, I want to be able to return this answer to the component that called this confirm so I can perform certain actions there.
My code looks like this:
This is the function I call from my component:
this._popup.confirmSaveTemp(this.modal);
This is the function with the confirm code. Currently I can print out OK or cancel in the two spots where I have placed "TODO".
confirmSaveTemp(modal, target, param){
console.log(target);
modal.confirm()
.size('lg')
.isBlocking(true)
.showClose(false)
.keyboard(27)
.title('Warning')
.body(`
<p><b>Some fields have been <span class="text-danger">marked with red</span> because of one or several following reasons:</b></p>
<ul>
<li>You forgot to fill out all input fields</li>
<li>Entered values are unrealistically high or low</li>
<li>Use of illegal characters (e.g. typing letters instead of numbers for a persons age)</li>
</ul>
<p><b>Please make sure that you have filled out the form correctly.</b></p>
<p>
<b>If you are finished entering all values for this page and want to permanently save, click <span class="text-success">Continue</span>.</b>
<br>
<b>If you expect to enter the remaining values at another time click <span class="text-warning">Save Temporarily</span></b>
</p>
<p></p>
`)
.footerClass('defaultPopupFooter')
.okBtn('Continue')
.cancelBtn('Save Temporarily')
.okBtnClass('btn btn-success')
.cancelBtnClass('btn btn-warning')
.open()
.then( (resultPromise) => {
resultPromise.result.then( (result) => {
//TODO - CALL SAVE FUNCTION
},
() => {
//TODO - SAVE TEMP
} );
});
}
* Question: How can I inform the "parent" component what the response of this dialogue is OR how can call a function from the "parent" component? *
You can pass functions as parameters like this from the parent class:
private okCallback() {
// do stuff on ok
}
private cancelCallback() {
// do stuff on cancel
}
openModal() {
// ...
this._popup.confirmSaveTemp(
this.modal,
target,
param,
this.okCallback.bind(this),
this.cancelCallback.bind(this)
);
}
And in the confirmSaveTemp:
confirmSaveTemp(modal, target, param, okCallback, cancelCallback){
console.log(target);
modal.confirm()
// ...
.open()
.then( (resultPromise) => {
resultPromise.result.then( (result) => {
//TODO - CALL SAVE FUNCTION
},
() => {
//TODO - SAVE TEMP
} );
})
// on OK click
.then(okCallback)
// on Cancel click
.catch(cancelCallback);
}
Related
I have a delete icon of an element which shows a modal to ask for the users approval. Once the user approves it should fire another function to delete another element.
First I call the modal
// Function to delete a benefit
$('.delete-benefit').on('click', function(e) {
let id = $(this).closest('.benefit-wrapper-id').attr('id'); // Get the id
call_modal('Delete Benefit', 'Are you sure you want to delete the Benefit?', delete_benefit(id))
// Only execute this function if modal's button with id 'confirm-button' was clicked
delete_benefit(id) // Delete the benefit
})
// Call the modal
function call_modal(title, text, func) {
$('#modalTitle').html(title) // Set some texts
$('#modalText').html(text) // Set some texts
$('#modal-wrapper').show() // Open it
}
// Eventlistener for the modal to execute the passed function upon approval
// Execute the passed function on confirm
document.getElementById("confirm-button")
.addEventListener("click", () => {
func()
}, false);
I tried to pass the delete_benefit(id) function to the modal but this somehow didn't work out as intended (as I want to apply this logic to multiple functions using the same modal component). How to accomplish this / what is a typical workflow here?
In this approach I'm passing information about what should happen when pressing the confirm button directly to the button element itself, via data-attributes:
// Function to delete a benefit
$('.delete-benefit').on('click', function(e) {
let id = $(this).closest('.benefit-wrapper-id').attr('id'); // Get the id
call_modal('Delete Benefit', 'Are you sure you want to delete the Benefit?', 'delete', id)
})
// Call the modal
function call_modal(title, text, intent, id) {
$('#confirm-button').attr('data-intent', intent) // WHAT SHOULD THE CONFIRMATION DO
$('#confirm-button').attr('data-id', id) // WHICH ID IS AFFECTED BY THE CONFIRMATION
$('#modalTitle').html(title) // Set some texts
$('#modalText').html(text) // Set some texts
$('#modal-wrapper').show() // Open it
}
// Eventlistener for the modal to execute the passed function upon approval
// Execute the passed function on confirm
document.getElementById("confirm-button").addEventListener("click", function() {
let intent = $(this).attr('data-intent')
switch (intent) {
case 'delete':
delete_benefit($(this).attr('data-id'))
break;
}
$(this).attr('data-intent', '')
$(this).attr('data-id', '')
}, false);
function delete_benefit(id) {
console.log('Delete benefit: ', id)
}
#modal-wrapper {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="benefit-wrapper-id" id="35">
<button class="delete-benefit">delete</button>
</div>
<div id="modal-wrapper">
<div id="modalTitle"></div>
<div id="modalText"></div>
<button id="confirm-button">Confirm</button>
</div>
In vue, would it be possible to update element text when $emit function has been triggered inside the element?
Here is a code snippet:
<a href="#" #click="fire('openCrudRoleModal',{{$role}})"
#updateRoleName="change text in this <a>">{{$role->name}}</a>
Within Laravel blade loop, I am generating links. Inside link I got vue click event, when clicked, it opens a modal with form.
After I update record (with ajax), I am triggering this.$emit('updateRoleName',response.name);
It would be nice if I could update the link text, which was clicked, without any additional vm methods.
Any thoughts..., can this be done?
Fallowing suggestions, I stopped at this solution. Not the best, but kind of works.
So in Laravel blade I am generating link, here I can also do the roles/permission check:
<th>
#can('edit role') <role-name-link :role="{{$role}}" /> #endcan
</th>
Inside <role-name-link />
<template>
{{name}}
</template>
<script>
export default {
props: ['role'],
name: "RoleNameLink",
data() {
return {
name: this.role.name
}
},
methods: {
open(){
Event.fire('openCrudRoleModal',this.role);
},
updateName(e){
this.name = e.name;
}
},
created() {
Event.listen('updateRoleName', (role) =>{
if(this.role.id == role.id) this.name = role.name;
});
}
}
</script>
Once link is clicked on, it will open a modal with update form. After update is completed it will $emit (Event.fire()) another event to update link text.
onSubmit(){
this.spinner = this.form.processing;
this.form[this.action]('/admin/roles/')
.then(response => {
this.$toastr.s('Role '+this.actionName[this.action]);
if(this.action == 'patch') Event.fire('updateRoleName',response);
this.hide();
});
}
Back inside <role-name-link />, I still need to compare id's if(this.role.id == role.id) this.name = role.name;, else it will update all names in the table.
This will update the name in the php generated table. One gotcha there is, if I click the same link again, inside form it will show me the original name that was echoed by php.
Any thoughts, suggestions. How to make it better.... more elegant?
I've made a function, which will be called when a button is clicked. I want to use it for two buttons, but after implementing it, when I click on one button, both get clicked at the same time?
This is the function, which will be called after onClick -
showMore = () => {
this.setState((prevState) => {
return { showMore: !prevState.showMore };
});
};
This is the condition I've used to call those two buttons (I know, I can do something here to make it just two if conditions rather than 4, suggestions?)
if (!this.state.showMore) {
accounts = take(accounts['demo_accounts'], DEFAULT_NO_OF_ACCOUNTS);
}
if (this.state.showMore) {
accounts = accountsData['demo_accounts'];
}
if (!this.state.showMore) {
cardNumbers =
take(cardNumbers['demo_numbers'], DEFAULT_NO_OF_ACCOUNTS);
}
if (this.state.showMore) {
cardNumbers = accountsData['demo_numbers'];
}
And I am using it for 2 buttons, however, both the buttons are getting clicked at the same time, I know I can use an ID for button, but that doesn't seen to work as well.
To sum it up, two questions basically -
How to reduce the 'if' statements?
How to stop both the buttons getting clicked?
Similar answer, but you can set it so that each button has a different ID and attaches to a different event handler, like so:
<button id="btn1">Click me!</button>
<button id="btn2">Me too!</button>
Javascript:
const button1 = document.getElementById("btn1").addEventHandler('click', function);
const button2 = document.getElementById("btn2").addEventHandler('click', function2);
How to reduce the 'if' statements?
Just combine the like conditions. Since all your conditions are basically checking the value of this.state.showMore you really only need 1 single conditional test.
if (this.state.showMore) {
accounts = accountsData['demo_accounts'];
cardNumbers = accountsData['demo_numbers'];
} else {
accounts = take(accounts['demo_accounts'], DEFAULT_NO_OF_ACCOUNTS);
cardNumbers =
take(cardNumbers['demo_numbers'], DEFAULT_NO_OF_ACCOUNTS);
}
How to stop both the buttons getting clicked?
When I want to use a single general click handler across multiple buttons I use a Higher Order Function, which is a function that returns a function. So in this case I create a clickHandler = id => () => this.setState({ [id]: <value> });
This callback takes an id parameter that is used when attaching the callback to the onClick handler of an element, and it is invoked right away and returns a new function that is actually used as the callback with the id saved in the enclosure.
<button onClick={this.clickHandler('a')>Button A</button>
<button onClick={this.clickHandler('b')>Button B</button>
Here is a codesandbox example of a HOF handler
I have two components here, the first one is a table, and I have an on-click event attached to one of the <td>'s in every row that summons a little tooltip-like window:
<td onClick={ () => loadSelectorWindow(p.product_id) }>
{
p.selectorActive &&
<SelectorWindow
cancelWindow={this.cancelSelectorWindow}
product_id={p.product_id}/>
}
</td>
The function bound to the <td> click will search through all products in state and flip a boolean on the selected product to display the tooltip.
loadSelectorWindow = (product_id) => {
this.setState({ products: this.state.products.map( p => {
if (p.product_id == product_id) {
p.variationSelectorActive = true
} else {
p.variationSelectorActive = false
}
return p
})})
}
However, the tooltip also needs a button with a window cancel event linked to it:
// within <SelectorWindow />
<p onClick={ () => {cancelWindow(event)} }> X </p>
This function cycles through state and sets all of the display booleans to false.
cancelSelectorWindow = (event) => {
event.stopPropagation()
this.setState ({ products: this.state.products.map( p => {
p.variationSelectorActive = false
return p
})})
}
Putting breakpoints in the code I can see that the cancel button is correctly calling the cancel function and setting the displayTooltip boolean to false, temporarily. The problem is, the loadSelectorWindow is ALSO getting fired when the cancelWindow button is clicked, and the boolean is set back to true DX.
This is why I attempted to put the event.stopPropagation call in there but obviously something is still calling it. There is no other place in my code that the loadSelectorWindow function is mentioned... Any ideas how I can stop it from getting called?
I forgot to pass event to the cancelWindow callback function. React why is your syntax so confusing sometimes...
Fix:
<p onClick={ (event) => {cancelWindow(event)} }> X </p>
You have one html element nested inside the other, so if you click the inner one then you will receive onClick events for both. So that is what you are getting. You need to redesign the layout of the page so that does not happen.
I have two html buttons in my jsp. One is Add and another is Remove.
Now If ony of the button is clicked then one dojo confirm dialog would be displayed. On click of 'Ok' in the dialog either Add or Remove Functionality will be executed. And this Dojo Dialog in present in one of the parent jsp page which will be reused by other jsp pages where Add or Remove functionlity is present. Depening on the Add/Remove button click the confirm message also needs to be changed. Ex. for Add, the message should be 'Do you want to Add' , for Remove the message would be 'Do you want to Remove'. I am able to set the message dynamically in the DOJO Cinfirm Dialog but not able to set the onExecute callback function ie. when Ok will be clicked in teh Dialog. Below id the code.
NB: I am using DOJO 1.10 library
Confirm Dialog Code:
require(["dijit/ConfirmDialog", "dojo/domReady!"], function(ConfirmDialog){
myDialog = new ConfirmDialog({
title: "GCLDW - Confirm Dialog",
content: "",
style: "width: 300px;",
onExecute:function(){
removeCustomer();
}
});
});
HTML Button Code:
<button type="button" id="removeCustomerButton"
onclick="myDialog.set('content', 'Do you want to remove the selected item ?<br><br>');myDialog.show();">
<SPAN class=grey><EM><s:message
code="customer.removeCustomer" text="" /></EM>
</SPAN>
</button>
<button type="button" id="addCustomerButton"
onclick="myDialog.set('content', 'Do you want to Add the selected item ?<br><br>');myDialog.show();">
<SPAN class=grey><EM><s:message
code="customer.addCustomer" text=""/></EM>
</SPAN>
</button>
Now how to set the onExecute call back function depending on the button click, either it would be addCustomer() or removeCustomer() , and whichever page is using this dialog will have their own implementation of these two method.
Just set the onExecute block- in the same way- how you are setting the content.
Also a suggestion is- put the JS code seperate from HTML.
Here goes the work-around-
HTML Code-
<button type="button" id="removeCustomerButton">
<SPAN class=grey><EM>Remove</EM></SPAN>
</button>
<button type="button" id="addCustomerButton">
<SPAN class=grey><EM>Add</EM></SPAN>
</button>
& the DOJO-
require(["dijit/ConfirmDialog", "dojo/domReady!"],
function(ConfirmDialog){
var myDialog = new ConfirmDialog({
title: "GCLDW - Confirm Dialog",
content: "",
style: "width: 300px;"
});
dojo.query('#removeCustomerButton').onclick( function() {
myDialog.set('content', 'Do you want to remove the selected item ?<br><br>');
myDialog.set('onExecute', function(){removeCustomer()} ); // cant call it directly- must wrap within a function
myDialog.show();
});
dojo.query('#addCustomerButton').onclick( function() {
myDialog.set('content', 'Do you want to Add the selected item ?<br><br>');
myDialog.set('onExecute', function(){addCustomer()} ); // cant call it directly- must wrap within a function
myDialog.show();
});
});
function removeCustomer(){
console.log("removeCustomer called on execute");
}
function addCustomer(){
console.log("addCustomer called on execute");
}
In /dojo-release-1.10.4-src/dijit/_DialogMixin.js, the comments state:
execute: function(/*Object*/ /*===== formContents =====*/){
// summary:
// Callback when the user hits the submit button.
// Override this method to handle Dialog execution.
I implemented a ConfirmDialog like so:
var confirmDialog = new ConfirmDialog({
title: core.confirm
});
confirmDialog.startup();
function confirmAction(text, callbackFn) {
confirmDialog.set("execute", callbackFn);
confirmDialog.set("content", text);
confirmDialog.show();
}
and called it as follows:
lib.confirmAction(core.areyousure, function () {
markedForDeletion.forEach(function (node) {
// Do deletion
});
});