JQuery Toggle .click function - onchange

I'm using jQuery Mobile. I have a toggle button that I need to launch a confirm dialog when the user clicks.
HTML
<div data-role="fieldcontain">
<div class='ui-grid-a' >
<div class='ui-block-a'>
<h4 rel='tooltip' title='Feature that automatically solves other values as you type in inputs' style='color:#cc0000;'>Auto-Solve</h4>
</div>
<div class='ui-block-b'>
<select name="togSwitch" id="autosolve" data-theme="" data-role="slider" data-mini="true">
<option value="off">Off</option>
<option selected value="on">On</option>
</select>
</div>
</div>
</div>
jQuery
$(document).ready(function() {
$('#autosolve').toggle(function() {
var answer = confirm('This will erase all current values. Are you sure you want to continue?');
if (answer === false) {return;} else {reset();}
}, function() {
var answer = confirm('This will erase all current values. Are you sure you want to continue?');
if (answer === false) {return;} else {reset();}
});
});
I've also tried to do a standard click function, but that did not work:
$('#autosolve').click(function() {
var answer = confirm('This will erase all current values. Are you sure you want to continue?');
if (answer === false) {
return;
} else {
reset();
}
});
I've also tried .change() but it launches onload, and it also displays a small select box underneath my toggleswitch, which is weird.
Does anyone know how to properly launch a confirm dialog once the user clicks on the toggle switch? And before the toggle changes

The toggle() function used that way was deprecated in jQuery 1.8 and removed in 1.9! You should probably hook into the built in events for the jQ mobile toggle switch :
$("#autosolve").on('slidestart', function(event) {
var answer = confirm('This will erase all current values....');
if ( answer ) reset();
return answer;
});

Related

Conditionally rendering icons only one time depending on property

I am trying to write a template that displays either Icon AAA or Icon BBB, depending on whether or not the item in the current iteration has a specific flag. Here is my code:
<div v-for="(item, itemIndex) in items">
<div v-if="item.hasUnreadComments">
<span>Display Icon AAA</span>
</div>
<div v-else>
<span>Display Icon BBB</span>
</div>
</div>
The issue here is that I need either icon displayed ONCE. If more than one item has it set to item.hasUnreadComments === true, Icon AAA will be displayed equally as many times, which is not what I want. Couldnt find anything in the docs and I dont want to bind it to a v-model.
Can this be done in Vue without a third data variable used as a flag?
You will have to do some sort of intermediate transformation. v-if is just a flexible, low-level directive that will hide or show an element based on a condition. It won't be able to deal directly with how you expect the data to come out.
If I'm understanding what you're asking for, you want an icon to only be visible once ever in a list. You can prefilter and use an extra "else" condition. This sounds like a use case for computed properties. You define a function that can provide a transformed version of data when you need it.
This example could be improved upon by finding a way to boil down the nested if/elses but I think this covers your use case right now:
const app = new Vue({
el: "#app",
data() {
return {
items: [{
hasUnreadComments: true
},
{
hasUnreadComments: true
},
{
hasUnreadComments: false
},
{
hasUnreadComments: true
},
{
hasUnreadComments: false
},
]
}
},
computed: {
filteredItems() {
let firstIconSeen = false;
let secondIconSeen = false;
return this.items.map(item => {
if (item.hasUnreadComments) {
if (!firstIconSeen) {
item.firstA = true;
firstIconSeen = true;
}
} else {
if (!secondIconSeen) {
item.firstB = true;
secondIconSeen = true;
}
secondIconSeen = true;
}
return item;
});
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="(item, itemIndex) in filteredItems">
<div v-if="item.firstA">
<span>Display Icon AAA</span>
</div>
<div v-else-if="item.firstB">
<span>Display Icon BBB</span>
</div>
<div v-else>
<span>Display no icon</span>
</div>
</div>
</div>

Vue.js Problem Controlling Div with v-show

I have four buttons and corresponding four divisions. On clicking first button, I want to display first div, on clicking the second button, I want to display the second div, and so on.
The button click event calls a method with the division number (0 through 3)
#click="showDiv(0)" for first button and #click="showDiv(1)" for the second button. This is my showDiv() method
showDiv: function(divNumber)
showDiv: function(divNumber)
{
this.showDetailsDiv.forEach(function(item, index, array) {
array[index]=null;
});
this.showDetailsDiv[divNumber] = true;
console.log(this.ShowDetailsDiv);
}
The initial value of showDetailsDiv prop is array with null values
showDetailsDiv: [
null,
null,
null,
null
],
In template, I am trying to control the divisions through v-show
<div v-show="showDetailsDiv[0]">
First div
</div>
<div v-show="showDetailsDiv[1]">
Second div
</div>
<div v-show="showDetailsDiv[2]">
Third div
</div>
When I click the button, I see that the corresponding element of showDetailsDiv is changing to true, however, the corresponding division does not display. Is there anything wrong in my logic?
When I try to control the display of division using direct properties (e.g. showDiv0, showDiv1, showDiv2 & showDiv3) with the following code, it works.
showDiv: function(divNumber)
{
this.showDetailsDiv.forEach(function(item, index, array) {
array[index]=null;
});
this.showDetailsDiv[divNumber] = true;
console.log(this.showDetailsDiv);
this.showDiv0= false;
this.showDiv1= false;
this.showDiv2= false;
this.showDiv3= false;
let elementID = 'showDiv' + divNumber;
this[elementID] = true;
}
<div v-show="showDiv0">
First div
</div>
<div v-show="showDiv1">
Second div
</div>
<div v-show="showDiv2">
Third div
</div>
Any suggestions?
Keep it simple. Template should look like:
<div v-show="visible == 0">
First div
</div>
<div v-show="visible == 1">
Second div
</div>
<div v-show="visible == 2">
Third div
</div>
data() {
return {
visible: null,
}
}
You can simplify showDiv method to:
showDiv: function(divNumber) {
this.visible = divNumber;
}
You can also add method isVisible to check which div is visible:
isVisible(divNumber) {
return this.visible == divNumber;
}
and use it like:
<div v-show="isVisible(0)">
First div
</div>
If you change an array element directly, Vue won't be able to detect the changes due to JavaScript limitations. You should be able to do it using the corresponding array method:
this.showDetailsDiv.splice(divNumber, 1, true);
You can find more ways of doing it here: https://v2.vuejs.org/v2/guide/list.html#Mutation-Methods
Also, if showDetailsDiv is a prop, you should probably avoid modifying it and create a copy in the component data instead.

Aurelia Dialog not returning response after using dropdown

I'm using the aurelia-dialog plugin to allow users to generate a set of objects, and want the dialog's response to return the chosen objects.
The workflow is that the list of options is generated from an API call using a promise when the activate() method is called on the dialog. The options are then displayed to the user, and selected from a dropdown. The user then clicks ok and the response should be sent back. Here is the code that is supposed to accomplish it:
this.ds.open({
viewModel: MyModal,
model: {
"title": "Select Objects",
"message": "I hate this modal"
}
}).then(response => {
console.log("closed modal");
console.log(response);
if (!response.wasCancelled) {
console.log('OK');
} else {
console.log('cancelled');
}
console.log(response.output);
});
And then in the modal.js:
import {inject} from 'aurelia-framework';
import {DialogController} from 'aurelia-dialog';
import {ModalAPI} from './../apis/modal-api';
//#inject(ModalAPI, DialogController)
export class MyModal {
static inject = [DialogController, ModalAPI];
constructor(controller, api){
this.controller = controller;
this.api = api;
controller.settings.centerHorizontalOnly = true;
}
activate(args){
this.title = args.title;
this.message = args.message;
this.returnedSet = null;
this.historicSetName = null;
this.reportHist = null;
return this.api.getReportHistory().then(reports => {
this.reportHist = reports;
});
}
selectHistoricReport() {
console.log(this.historicSetName);
if(this.historicSetName == "Select a report...") {
this.returnedSet = null;
} else {
var selectedReport = this.reportHist.filter(x => x.name == this.historicSetName)[0];
this.returnedSet = selectedReport.rsids;
}
console.log(this.returnedSet);
}
ok(returnedSet) {
console.log(returnedSet);
this.controller.ok(returnedSet);
}
}
And then the html:
<template>
<require from="../css/upload-set.css"></require>
<ai-dialog class="selector panel panel-primary">
<ai-dialog-header class="panel-heading">
<button type="button" class="close" click.trigger="controller.cancel()" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">${title}</h4>
</ai-dialog-header>
<ai-dialog-body class="panel-body container-fluid">
<div class="row">
<div class="col-sm-6">
<label>Report: </label>
<select value.bind="historicSetName" change.delegate="selectHistoricReport()" class="input-md form-control">
<option ref="historicSetPlaceholder">Select a report...</option>
<option repeat.for="historicReport of reportHist">${historicReport.name}</option>
</select>
</div>
</div>
</ai-dialog-body>
<ai-dialog-footer>
<button click.trigger="controller.cancel()">Cancel</button>
<button click.trigger="ok(returnedSet)">Save</button>
</ai-dialog-footer>
</ai-dialog>
</template>
As long as I don't touch the dropdown, the dialog will return a null (or any other value I initialize returnedSet to). However, as soon as I click on the dropdown, clicking either the Save or Cancel button leads to nothing being returned and the console.log lines at the end of my first code block just get skipped. I also tried removing the click.delegate line from my HTML, but that didn't change anything.
Anyone have any idea why this might be happening?
Also, I found this post(Aurelia Dialog and Handling Button Events) with an extremely similar problem, but can't seem to find any solution in there as to what I should do.
Thanks in advance.

How to catch a return on an input element using Aurelia?

In angularjs I had the following:
app.directive('ngEnter', function () {
return function (scope, element, attrs) {
element.bind("keydown keypress", function (event) {
if(event.which === 13) {
scope.$apply(function (){
scope.$eval(attrs.ngEnter);
});
event.preventDefault();
}
});
};
});
And the html was:
<input type="text" ng-model="searchText" class="form-control"
placeholder="Search"
ng-enter="search($event, searchText)">
So basically once I have finished typing my text to search on, when I pressed the enter key the search function on my controller would run.
How would I do this in Aurelia?
I am still learning about its features so any help would be appreciated.
I think an alternative to the angular ngEnter would be:
import {customAttribute, inject} from 'aurelia-framework';
#customAttribute('enter-press')
#inject(Element)
export class EnterPress {
element: Element;
value: Function;
enterPressed: (e: KeyboardEvent) => void;
constructor(element) {
this.element = element;
this.enterPressed = e => {
let key = e.which || e.keyCode;
if (key === 13) {
this.value();//'this' won't be changed so you have access to you VM properties in 'called' method
}
};
}
attached() {
this.element.addEventListener('keypress', this.enterPressed);
}
detached() {
this.element.removeEventListener('keypress', this.enterPressed);
}
}
<input type="password" enter-press.call="signIn()"/>
The simplest way would be to wrap the input in a form element and bind to the submit event of the form.
<form role="form" submit.delegate="search()">
<div class="form-group">
<label for="searchText">Search:</label>
<input type="text" value.bind="searchText"
class="form-control" id="searchText"
placeholder="Search">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
This will give you the same behavior you have built above. I'm still working to create an example of a custom attribute to do this, but honestly, this is how I would recommend you do this specific thing (capturing when the user presses enter).
This does not seem to be supported out of the box. While not perfect, here is what I intend to do:
Add a hidden submit button at the top of my form with a click.delegate attribute.
Run some code in my VM when its clicked. This code will decide what to do with the enter keypress based on any custom logic I need.
Hope that helps,
Andrew
EDIT:
You could also add a keypress event delegate:
<input keypress.delegate="doSomething($event)" />
And define doSomething() as:
doSomething(event) {
if(event.which == 13) {
alert('Your code goes here!');
}
event.preventDefault();
}
This will be a little cleaner when you have many inputs with differing enter keypress behaviours.
Because of keypress.delegate and keypress.trigger in an <input> block entering text by default, your function must return true to avoid it, like this:
doSomething(event) {
if(event.which == 13) {
console.log('Your code goes here!');
event.preventDefault();
return false;
}
return true;
}

How can I show different Views in their corresponding tabs?

It doesn't matter which tab I click on, it doesn't show anything. I want to show the View in its corresponding tab. I don't know what to put between <div id="tab...">**HERE**</div> to show the View (see complete code bellow)
The View looks like this:
<ul id="tabs">
<li>#Html.ActionLink("Random stuff", "TabbedIndex?claimed=false", "Stuff", null, new { name = "tab1" }) </li>
<li>#Html.ActionLink("Special stuff", "TabbedIndex?claimed=true", "Stuff", null, new { name = "tab2" }) </li>
</ul>
<div id="content">
<div id="tab1"></div>
<div id="tab2"></div>
</div>
This is my script:
<script>
$(document).ready(function () {
$("#content").find("[id^='tab']").hide(); // Hide all content
$("#tabs li:first").attr("id", "current"); // Activate the first tab
$("#content #tab1").fadeIn(); // Show first tab's content
$('#tabs a').click(function (e)
{
e.preventDefault();
if ($(this).closest("li").attr("id") == "current") { //detection for current tab
return;
}
else {
$("#content").find("[id^='tab']").hide(); // Hide all content
$("#tabs li").attr("id", ""); //Reset id's
$(this).parent().attr("id", "current"); // Activate this
$('#' + $(this).attr('name')).fadeIn(); // Show content for the current tab
}
});
});
</script>
Assuming both tabs are hidden at load time, you can try this:
<script>
$('#tabs a').click(function (e)
{
e.preventDefault();
var name = $(this).attr("name"), tab = $("#" + name);
if (tab.is(":visible")) {
//if the tab is visible, do nothing
return;
}
else {
// show the selected tab and hide all the siblings/neighbours tabs
tab.show().siblings().hide();
}
});
</script>
This is the solution, I didn't change anything in the original code and script:
<div id="content">
<div id="tab1">#{ Html.RenderAction("TabbedIndex", "Stuff", new { claimed = false }); }</div>
<div id="tab2">#{ Html.RenderAction("TabbedIndex", "Stuff", new { claimed = true }); }</div>
</div>