Prevent dropdown close when click outside - vue.js

I created a CDropdown with a CInput inside. I don't want the dropdown auto close when I click outside because I want to copy text somewhere and paste to CInput. How can that be? Thanks for your help.
<CDropdown :show.sync="isShow">
<template>
<CInput
label="Sample label"
type="text" />
</template>
</CDropdown>

Finally I do it by read sourcecode of CDropdown and do workaround:
First, set ref to CDropdown:
<CDropdown ref="refDropdown" :show.sync="isShow">
Then override hide() function of CDropdown, be sure to call $forceUpdate() to update the directive of CDropdown:
this.$refs.refDropdown.hide = function() {
console.log("Prevented hide");
}
this.$refs.refDropdown.$forceUpdate();

Related

How to disable blur call on the active element from SwiperJS in onTouchStart handler?

Is it possible to disable this blur call on the active element from SwiperJS in the onTouchStart event handler?
Some background:
For touch and desktop devices I'm using swiper for forms on swiper-slides. Within a form I'm using vue-select (a combobox).
The Problem: When the user selects an entry, the entry get not selected on the first time but on the second time.
<div class="swiper-container">
<div class="swiper-wrapper">
<div class="swiper-slide">
<div>First form</div>
<v-select :options="selectionEntries"></v-select>
</div>
<div class="swiper-slide">
<div>Second form</div>
<v-select :options="selectionEntries"></v-select>
</div>
</div>
</div>
See also this example on codepen
I figured out that it seems to work correctly:
When I remove the blur-listener on the input field of the vue-select box. But it is used to close the selection list when the user leaves the field.
When I comment out this blur call in SwiperJS. I'm not sure why it is used there.
The first point is not an option, so is it possible to disable the blur call of SwiperJS via configuration?
Currently I'm using this workaround (SwiperJS V6.4.1):
const swiper = new Swiper(".swiper-container", {
// Workaround part 1:
touchStartPreventDefault: false
})
// Workaround part 2:
swiper.touchEventsData.formElements = 'notExistingHtmlTagName'
Part 1: To handle mouse down and click events on all elements, set the swiper parameter touchStartPreventDefault: false.
That will disable this code block: https://github.com/nolimits4web/swiper/blob/9dead9ef4ba5d05adf266deb7e3703ceb199a241/src/components/core/events/onTouchStart.js#L90-L97
Part 2: Set swiper.touchEventsData.formElements = 'undefined' to define nothing as formElements. That will disable the code block that calls blur: https://github.com/nolimits4web/swiper/blob/9dead9ef4ba5d05adf266deb7e3703ceb199a241/src/components/core/events/onTouchStart.js#L81-L88

XPages - Bootstrap popover

I have an icon, which when you hover, pops up some extra information in a bootstrap popover
This works as expected, however, if I then click on any field on the page, which then does a partial refresh of a div containing the icon, it then loses the hover functionality.
Icon code:
<!--INFO BUTTON START-->
<xp:text escape="false" id="computedField4">
<xp:this.value><![CDATA[#{javascript:try{
var text = #DbLookup(#DbName(), "LookupKeywordLists", "Info"+compositeData.fieldName, "Members");
return " <i class='fa fa-info-circle' data-container='body' data-toggle='popover' data-trigger='hover' data-placement='right' data-content='"+text+"'></i>"
}catch(e){
openLogBean.addError(e,this.getParent());
}
}]]></xp:this.value>
<xp:this.rendered><![CDATA[#{javascript:try{
return compositeData.showInfoIcon;
}catch(e){
openLogBean.addError(e,this.getParent());
}}]]></xp:this.rendered>
</xp:text>
<!--INFO BUTTON END-->
Script block on the page:
<xp:scriptBlock id="scriptBlock1">
<xp:this.value><![CDATA[$(document).ready(function(){
$('[data-toggle="popover"]').popover({
trigger: 'hover',
title: 'Information'
});
});]]></xp:this.value>
</xp:scriptBlock>
The script block is currently outside the div that the partial refresh "refreshes" however I tried putting it within the div, which didn't resolve the issue. Any ideas? Thanks
You need to add the popover when the partial refresh occurs. In order to do so you use Dojo to subscribe to the partialrefresh-complete event.
This answer can help you: https://stackoverflow.com/a/49014247/785061.

access local variable within *ngIf

I have a primeng (angular 2) dialog with a dropdown. I want to set focus to the dropdown when the dialog shows. The problem appears to be that my div is rendered conditionally.
My code:
<p-dialog (onShow)="fe.applyFocus()">
<div *ngIf="selectedItem">
<button pButton type="button" (click)="fe.applyFocus()" label="Focus"></button>
<p-dropdown #fe id="reason" [options]="reasonSelects" [(ngModel)]="selectedReason" ></p-dropdown>
</div>
</p-dialog>
In this code the button works fine, but the onShow() (outside the *ngIf div) tells me fe is undefined.
How can I access the local variable inside the *ngIf?
Yes, this is a real pain. Unfortunately, due to the way *ngIf works, it completely encapsulates everything inside (including the tag it's on).
This means anything declared on, or inside, the tag with the ngIf will not be "visible" outside of the ngIf.
And you can't even simply put a #ViewChild in the ts, because on first run it might not be present... So there are 2 known solutions to this problem...
a) You can use #ViewChildren. This will give you a QueryList that you can subscribe to, which will fire off every time the tempalte variable changes (ie. the ngIf turns on or off).
(html template)
<div>{{thing.stuff}}</div>
<my-component #thing></my-component>
(ts code)
#ViewChildren('thing') thingQ: QueryList<MyComponent>;
thing: MyComponent;
ngAfterViewInit() {
this.doChanges();
this.thingQ.changes.subscribe(() => { this.doChanges(); });
}
doChanges() {
this.thing = this.thingQ.first;
}
b) You can use #ViewChild with a setter. This will fire the setter every time the ngIf changes.
(html template)
<div>{{thing.stuff}}</div>
<my-component #thing></my-component>
(ts code)
#ViewChild('thing') set SetThing(e: MyComponent) {
this.thing = e;
}
thing: MyComponent;
Both of these examples should give you a "thing" variable you can now use in your template, outside of the ngIf. You may want to give the ts variable a different name to the template (#) variable, in case there are clashes.
You can separate the use of template on NgIf level:
<ng-container *ngIf="selectedItem; else elseTemplate">
<p-dialog (onShow)="fe.applyFocus()">
<div>
<button pButton type="button" (click)="fe.applyFocus()" label="Focus"></button>
<p-dropdown #fe id="reason" [options]="reasonSelects" [(ngModel)]="selectedReason"></p-dropdown>
</div>
</p-dialog>
</ng-container>
<ng-template #elseTemplate>
<p-dialog>
</p-dialog>
</ng-template>

Aurelia checkbox inside a button

I am trying to have a checkbox inside a button and both clicking on the checkbox or the button should toggle the checkbox and the boolean value bound to it from the view model.
app.html:
<template>
<h1>${heading}</h1>
<button type="button" click.trigger="toggleIsChecked()">
<input type="checkbox" checked.bind="isChecked"> ${isChecked}
</button>
</template>
app.ts:
export class App {
isChecked: boolean;
toggleIsChecked() {
this.isChecked = !this.isChecked;
}
}
What happens is that when I click the button (outside the checkbox) everything works as expected. But when I click the checkbox the boolean value in the view model changes but the checkbox is not checked or unchecked. What could be causing this?
I have tried different approaches but they all produce similar results. While debugging I noticed the checkbox gets checked but something in the Aurelia framework removes it almost instantly. Seems like the event handling is not working properly?
EDIT: I made a gist so you can try it yourself: https://gist.run/?id=4a7b2c11db33bdb37213eb4ea1b5b2b0
It's not the Aurelia framework that is "removing" the checking. What is happening is that when you click the checkbox, the isChecked is automatically set to true, then toggleIsChecked() is fired and isChecked is set to false (isChecked is set twice when you click the checkbox). To solve this you have to not set isChecked if the target is the checkbox. Something like this:
JS
toggleIsChecked(event) {
if (event.target.tagName === 'INPUT') {
return true; //checkbox has been clicked, do nothing!
}
this.isChecked = !this.isChecked;
}
HTML
<button type="button" click.trigger="toggleIsChecked($event)">
<input type="checkbox" checked.bind="isChecked"> ${isChecked}
</button>
Same explanation with Fabio Luz & going to do the same thing, but instead of checking event target tag name, You can use self binding behavior, like this
<template>
<require from='./self'></require>
<h1>${heading}</h1>
<button type="button" click.delegate="toggleIsChecked() & self">
<input type="checkbox" checked.bind="isChecked"> ${isChecked}
</button>
</template>
What self binding behavior does here is to ensure toggleIsChecked only fires when you click on button itself, not its descendant, same with this block of code:
toggleIsChecked(event) {
if (event.target === this.button) {
// Do your thing
}
}
Note: self just got merged, but has not been released yet. I have included the code at this gist: https://gist.run/?id=5e66dfd996d852344a524010ae82a936
You can read more about the PR here: https://github.com/aurelia/templating-resources/pull/263
Kind people at the Aurelia Gitter chat provided me with an answer. What is happening in my gist is that the default event handler is not being called. Reason for this is that Aurelia automatically calls the event.preventDefault() function. In order for the default event handler to be called I must return true from my own event handler. Here's a working gist proving how it works: https://gist.run/?id=3cb545572065cffd737f98788a4105a1
Thank you all for your answers. I decided to answer this myself since I got the answer from the Gitter chat, but the kudos belongs to the awesome Aurelia community and especially #CasiOo.

JavaScript .innerHTMLworking only when called manually

I've got a very simple function, of replacing the innerHTML of a element. I've been trying to debug this for hours but simply can't, and it's infuriating.
When called from a button press the JavaScript (as follows) works well, but when called from another function it doesn't work. I am totally lost as to why this might be, and its a fairly core part of my app
// This loaded function in my actual code is a document listener
// checking for when Cordova is loaded which then calls the loaded function
loaded();
function loaded() {
alert("loaded");
changeText();
}
function changeText() {
alert("started");
document.getElementById('boldStuff').innerHTML = 'Fred Flinstone';
}
Button press and HTML to replace
<div id="main">
<input type='button' onclick='changeText()' value='Change Text'/>
<p>Change this text >> <b id='boldStuff'> THIS TEXT</b> </p>
</div>
It is also here in full on JSFiddle
You are already changed the innerHTML by calling the function loaded(); on onLoad.
Put this in an empty file and same as .html and open with browser and try. I have commented the function loaded();. Now it will be changed in onclick.
<div id="main">
<input type='button' onclick='changeText();' value='Change Text'/>
<p>Change this text >> <b id='boldStuff'> THIS TEXT</b> </p>
</div>
<script>
//loaded();
function loaded() {
alert("loaded");
changeText();
}
function changeText() {
alert("started");
document.getElementById('boldStuff').innerHTML = 'Fred Flinstone';
}
</script>
The problem here is, that the element you're trying to manipulate is not yet existing when you are calling the changeText() function.
To ensure that the code is only executed after the page has finished loading (and all elements are in place) you can use the onload handler on the body element like this:
<body onload="loaded();">
Additionally you should know, that it's very bad practice to manipulate values by using the innerHTML property. The correct way is to use DOM Manipulations, maybe this can help you.
You script loads before the element (boldStuff) is loaded,
Test Link - 1 - Put the js in a seperate file
Test Link - 2 - put the js at the very end, before closing the <body>