Show commands' labels in AppBar with More button - javascript

So I've got myself an AppBar in my WinJS UWP app
<div data-win-control="WinJS.UI.AppBar" id="appBar" data-win-options="{ closedDisplayMode : 'compact', placement:'bottom'}">
<button data-win-control="WinJS.UI.AppBarCommand"
data-win-options="{id:'flyoutButton',
type:'flyout',
label:'Třída',
icon:'otheruser',
flyout:select('#classFlyout')}"></button>
<button data-win-control="WinJS.UI.AppBarCommand"
data-win-options="{id:'flyoutButton',
type:'flyout',
label:'Schovávání hodin',
icon:'calendarday',
flyout:select('#hidingFlyout')}"></button>
<button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id:'moreButton',label:'More',icon:'more',section:'primary',tooltip:'Show more'}"></button>
</div>
It has two flyouts and a button. When I click the button, I want the the other commands' labels to be visible - as in the Win10 Weather app.
I've tried to create a function, that would change the appbar's closedDisplayMode to 'full'.
WinJS.UI.processAll().done(function () {
appBar = document.getElementById("appBar");
});
function addListeners() {
document.getElementById("moreButton").addEventListener("click", openCloseAppbar, false);
}
function openCloseAppbar() {
appBar.closedDisplayMode = 'full';
}
That, however, doesn't work. Is there an other way this is usually done that I'm missing? (Because for some reason I can't find any documentation on it.) Or am I just doing it wrong..?

The correct way to do it was apparently this:
appBar.winControl.closedDisplayMode = "full";
(Emphasis on .winControl.)

Related

typescript scroll position

In my angular UI code, I have a component class that calls a like below
app.component.html
//...
<div class="banner">
<p-dialog [(visible)]="displayCOI" styleClass="coiDialog" [contentStyle]="{'overflow-y': 'hidden'}" [modal]="true" [style]="{width: '75vw'}" [baseZIndex]="10000" [showHeader]="false"
[draggable]="false" [resizable]="false">
<coi (notify)="onCoIAccept($event)"></coi>
</p-dialog>
</div>
...///
coi.component.html looks like below
<div>
<div class="row" style="padding: 10px 0px">
<div class="col-sm-4">
<p align="center"><b>Instructions</b></p>
<br>...//
</div>
<div #scrollDiv id="scrollDiv" class="col-sm-6" style="height:350px; overflow-y: scroll;" (scroll)="onScroll($event)">
<p-table #dt [columns]="cols" [scrollable]="true" [value]="usersLi" [(selection)]="selectedUsersLi" dataKey="id">
//....
..///
</p-table>
</div>
<div class="col-sm-2">
<div align="center">
<button pButton type="button" label="Accept" [disabled]="disableAccept" (click)="close()" class="ui-button-rounded"></button>
</a>
</div>
</dv>
</div>
coi.component.ts code is as below:
export class coiComponent {
#ViewChild("scrollDiv") scrollDiv: ElementRef;
disableAccept: boolean = false;
ngOnInit():void {
this.keys = Object.keys(this.propertyObj);
this._utilService.convertKeysToHeader(this.keys,this.cols);
this.disableAccept = true;
this.loadRecords();
}
onScroll(event: any) {
// visible height + pixel scrolled >= total height
if (event.target.offsetHeight + event.target.scrollTop >= event.target.scrollHeight) {
this.disableAccept = false;
console.log("End");
}
}
ngOnChanges(changes: SimpleChanges){
console.log("ngOnChanges" , changes);
for ( const propName in changes){
let change = changes[propName];
if ( propName == 'coi'){
// console.log('CHANGED...DO HERE');
console.log(this.scrollDiv.nativeElement.offsetHeight);
console.log(this.scrollDiv.nativeElement.scrollHeight);
}
}
}
}
As you can see the modal is divided into 3 DIV. 1. instrucations, 2: table, 3. Accept button
The modal by itself has a fixed height and scroll hidden. The div with table has a fixed height and overflow scroll and it works perfectly. Now the table can be with 30-50 records so vertical scrolling is enabled. I want the accept button on the 3rd div to be enabled only when the user had scrolled the table and has seen all the records. So the function (scroll)="onScroll($event)" enables only when the scroll is scrolled completely and it works perfectly.
my question is Some users may see less than 5-10 records which means scroll wouldn't be enabled for those users and accept also need to be enabled for them. Any suggestion on how to do this, please? I tried adding an id for the div tag called "scrollDiv" and #scrollDiv and passing this as an ElementRef and on ngOnChange trying to get the offsetHeight and scrollHeight but I get value '0' on all the cases.` Can someone help me with this?
I have updated my question. Please give some suggestions. Thank you.
I'll try to give you a running idea, then you can understand and apply it to your case. You can check at this link.
Explanation of the example
In the component you have 4 important things to consider:
isActionDisabled a variable that says if your action should be disabled or not
#ViewChild('containerElement') containerElement a refer to the scrollable container of the table
onScrollContainer a method that's executed when you scroll the containerElement
disableByScroll a method that changes the value of isActionDisabled according to the position of the scrollbar of the containerElement. If it's on bottom isActionDisabled is false otherwise is true.
The most important method is disableByScroll:
disableByScroll(): void {
if (this.containerElement) {
const element = this.containerElement.nativeElement;
this.isActionDisabled = !(
element.scrollTop ===
element.scrollHeight - element.clientHeight
);
} else {
this.isActionDisabled = true;
}
}
Please read this article to understand what I did.
disableByScroll is called each time a scroll event is called on containerElement
onScrollContainer(): void {
this.disableByScroll();
}
and after view init
ngAfterViewInit(): void {
this.disableByScroll();
this.cdr.detectChanges();
}
That is useful if you have a number of items that do not activate the scrollbar. Please, read this guide to understand the lifecycle events of an Angular application. As you can see I called a method detectChanges of the ChangeDetectorRef. Reading that guide you'll understand why.
About the template, it's pretty simple and you can figure it out.

IOS show keyboard on input focus

I have a problem that i can't fix.
Keyboard doesn't show on input.focus() on IOS
searchMobileToggle.addEventListener('click', function() {
setTimeout(function(){
searchField.focus();
}, 300);
});
I've been looking for a solution with no result, i know this is a frequently unsolved question but i see NIKE (https://m.nike.com/fr/fr_fr/) and FOODSPRING (https://www.foodspring.fr/) doing it on mobile.
So i'm wondering how do they do ?
None of the other answers worked for me. I ended up looking into the Nike javascript code and this is what I came up with as a reusable function:
function focusAndOpenKeyboard(el, timeout) {
if(!timeout) {
timeout = 100;
}
if(el) {
// Align temp input element approximately where the input element is
// so the cursor doesn't jump around
var __tempEl__ = document.createElement('input');
__tempEl__.style.position = 'absolute';
__tempEl__.style.top = (el.offsetTop + 7) + 'px';
__tempEl__.style.left = el.offsetLeft + 'px';
__tempEl__.style.height = 0;
__tempEl__.style.opacity = 0;
// Put this temp element as a child of the page <body> and focus on it
document.body.appendChild(__tempEl__);
__tempEl__.focus();
// The keyboard is open. Now do a delayed focus on the target element
setTimeout(function() {
el.focus();
el.click();
// Remove the temp element
document.body.removeChild(__tempEl__);
}, timeout);
}
}
// Usage example
var myElement = document.getElementById('my-element');
var modalFadeInDuration = 300;
focusAndOpenKeyboard(myElement, modalFadeInDuration); // or without the second argument
Note that this is definitely a hacky solution, but the fact that Apple hasn't fixed this in so long justifies it.
I found a solution, click() didn't work, but i figured it out.
searchMobileToggle.addEventListener('click', function() {
if(mobileSearchblock.classList.contains('active')) {
searchField.setAttribute('autofocus', 'autofocus');
searchField.focus();
}
else {
searchField.removeAttribute('autofocus');
}
});
I was working with vue.js that was removing input autofocus attribute, when the component was loaded.
So i had it on click, but there was another problem, the autofocus only worked once, but combined with focus(), it now work all the time :)
Thanks for your help !
This really drives me/us crazy. It works fine on the Android phone, but something is disabled by the Apple developer. (I understand it's annoying to pop the keyboard when not necessary though).
I accidentally found out that the "popup" module from Semantic-UI fixes this magically.
Note that the solution works for SemanticUI (#semantic-ui team may tell what event makes this work)
Here are how I did:
const [search, setSearch] = useState(false);
const inputRef = useRef(null);
React.useEffect(() => {
if (search) {
inputRef.current.focus();
} else {
inputRef.current.blur();
}
}, [search]);
<div onClick={() => setSearch(true)}>
<Popup
content="Search for Swimmers and Time Standards."
offset={[-500, -1000]}
trigger={<Icon name="search" />}
/>
</div>
{search && <Input ref={inputRef} />}
As you see, I wrapped the trigger Icon with the Popup module, and hide the Popup content by setting the crazy offset. And then it magically works.
See the demo here: https://swimstandards.com/ (check it out on your iPhone)
Angular solution:
on button click we need to create temporary input, append to existing container (close to our input) and focus on it.
btnClicked() {
this.showModal = true;
this.searchBar = this.renderer2.selectRootElement('#searchBar', true);
// 2nd argument preserves existing content
// setting helper field and focusing on it
this.inputHelper = this.renderer2.createElement('input');
this.renderer2.appendChild(this.searchBar, this.inputHelper);
this.inputHelper.focus();
let event = new KeyboardEvent('touchstart',{'bubbles':true});
this.searchBarButton.nativeElement.dispatchEvent(event);
}
after modal/target input is shown, we move focus and remove temporary one:
initiateKeyboard() {
setTimeout(()=> {
this.searchBarInput.nativeElement.focus();
this.renderer2.removeChild(this.searchBar, this.inputHelper);
},180);
}
and template:
<div id="searchBar">
<input type="button" class="button is-link is-light" value="Search" (click)="btnClicked()" (touchstart)="initiateKeyboard()" #searchBarButton>
</div>
You just need to remember that iPhone may zoom screen, so you need to adjust parameters of temporary input.
working solution: https://inputfocus.vercel.app/
Worked in 2022 with ios 16!
OMG, I searched for so long and the above solution won't work for me.
Here is how it worked for me. I wrapped the input in a React FocusLock component. Check this package out: https://www.npmjs.com/package/react-focus-lock
Here is a small example:
<FocusLock>
<Input />
</FocusLock>
There is no legitimate way to do this since iOS kind of wants to only open the keyboard on a user interaction, however you can still achieve this with either using prompt() or using focus() from within a click() event it and will show up.

ag-grid onGridReady not working

I want to load ag-grid inside a button click. I have tried two approaches but none is working
My code : First Method
onBtnClick(){
this.gridOptions ={
onGridReady : function(){
console.log("print");
}
}
}
Second method:
onBtnClick(){
this.onGridReady();
}
onGridReady(){
this.gridApi = params.api;
console.log("print");
}
First method not working. Second method says api is not defined
You can have this approach.
Have a flag in your component when to display the grid.
Use this flag to conditionally display the grid using *ngIf
Set this flag value on button click
This way, the template having ag-grid won't be rendered until the flag is set. When it's set, the template will be rendered and onGridReady will be called.
<button (click)="btnClick()">Display grid</button>
<ag-grid-angular *ngIf="displayGrid"
#agGrid
......
></ag-grid-angular>
btnClick(){
this.displayGrid = true;
}
Check this working example: ag-grid display on button click
Have you checked if ag-gridis connected to onGridReady?
It should look something like that:
<ag-grid-angular
...
(gridReady)="onGridReady($event)"
>
</ag-grid-angular>
You should share more of you code, it's unclear what you are doing.
You must make sure your gridOptions are fully set up BEFORE the grid initializes. (Doing this on a button is too late)
ngOnInit(): void {
this.gridOptions.onGridReady = gridReadyHandler;
}
gridReadyHandler = (params: GridReadyEvent) => {
this.gridApi = params.api;
console.log("grid is done loading", this.gridApi);
}

Using ReactModal button with Href, not working. Unsure why

I am fairly new to react and have redone my personal site in react. The issue I am running into is my button that links (with href) to my JSfiddle for each portfolio demo is not working. I am not sure if I did not bind correctly or what exactly the issue is other than when the modal is open, the Demo button does not work. Close modal button works fine. Please see code below.
import React from 'react';
import ReactModal from 'react-modal';
class Project extends React.Component {
constructor () {
super();
this.state = {
showModal: false
};
this.handleOpenModal = this.handleOpenModal.bind(this);
this.handleCloseModal = this.handleCloseModal.bind(this);
}
handleOpenModal() {
this.setState({ showModal: true});
}
handleCloseModal() {
this.setState({ showModal: false});
}
componentWillMount() {
ReactModal.setAppElement('body');
}
render() {
const { details } = this.props;
return (
<li className="Project">
<div onClick={this.handleOpenModal}>
<img className="Project-image" src={'projects/' + details.image} alt={details.name}/>
<div className="Project-overlay">
<p>{details.name}</p>
</div>
</div>
<div >
<ReactModal
isOpen={this.state.showModal}
contentLabel="This is my Modal"
shouldCloseOnOverlayClick={true}
onRequestClose={this.handleCloseModal}
>
<div className="modal-header">
<h3>{details.name}</h3>
</div>
<div className="modal-body">
<img className="Project-image" src={'projects/' + details.image} alt={details.name} />
<p className="desc-body">{details.desc}</p>
<p className="desc-body">{details.link}</p>
</div>
<div className="modal-footer">
{ details.havLink && <button className="button" href={details.link}>Click for Demo!</button> }
<button className="button" onClick={this.handleCloseModal}>Close Modal</button>
</div>
</ReactModal>
</div>
<div className="Project-tag">
<p>{details.tag}</p>
</div>
</li>
)
}
}
const props = {};
export default Project;
The issue is in the first line of the "modal-footer" class. This button will show if the havLink property is true. This data is being exported from another JS file. Everything else (image, description, modal title) all import correctly, even the link I set imports correctly but when the button is pushed nothing fires as I expected. I do not see any errors in my React dev tools either.
{details.link} as an href is not routing me to the specified link. The link will show up in the paragraph tag though (just to see if correct link populated).
Let me know if anything else is needed, I am hoping the solution is as simple as an incorrect binding. Thank you in advance!
<button> does not have the href attribute. You should be using an anchor element <a>. To the anchor you can pass whatever class or style you want to make it look like a button, but it's still an anchor element, not button.

"el.closest is not a function at getScrollTarget", using Quasar Framework (Vue)

My modal consists of cards which works fine. Now I want to have the 'active' card at the top of the viewport when the modal opens. I am trying to do this using getScrollTarget and setScrollPosition but I get the following error:
Uncaught TypeError: el.closest is not a function at getScrollTarget (quasar.esm.js?8bfb:1384)
at VueComponent.open (ModalTest.vue?4a7f:120)
at VueComponent.boundFn [as open] (vue.runtime.esm.js?ff9b:165)
at VueComponent.openModal (Maplayout.vue?1988:60)
at VueComponent.boundFn [as openModal] (vue.runtime.esm.js?ff9b:165)
at Vue$3.eval (Maplayout.vue?1988:47)
at Vue$3.Vue.$emit (vue.runtime.esm.js?ff9b:2202)
at Object.$emit (quasar.esm.js?8bfb:198)
at HTMLElement.emitEventFunction (util.js?93ee:587)
The modal component looks like this:
<template>
<q-modal ref="myModal" maximized>
<q-modal-layout class="scroll">
<div class="layout-padding">
<q-card inline
center
style="min-width: 90vw"
v-for="test in tests"
:key="tests.id"
>
<q-card-media>
<img :src="test.getAttribute('image')">
</q-card-media>
<q-card-main>
<div>{{ test.getAttribute('myAttribute') }}</div>
</q-card-main>
</q-card>
</div>
</q-modal-layout>
</q-modal>
</template>
<script>
import {
QCard,
QCardMain,
QCardMedia,
QModal,
QModalLayout,
scroll
} from 'quasar'
const {getScrollTarget, setScrollPosition} = scroll
export default {
name: 'myModal',
components: {
QCard,
QCardMain,
QCardMedia,
QModal,
QModalLayout,
scroll
},
computed: {
...myState({
tests: state => state.mymodule.tests
})
},
methods: {
open () {
this.$refs.myModal.open()
const element = document.getElementById('feature-listing').getElementsByClassName('item-image active')
console.log('element: ', element)
setScrollPosition(getScrollTarget(element), 0, 200)
}
}
}
</script>
The output of the console.log gives following about the element that is active in the console:
[div#98729.item-image.js-fade.my-quick-fade-in.active, 98729: undefined]
I do not quite understand the 'undefined' part... (the length of the array is 1..., so maybe not relevant or something...?!), as the div can be opened in the console and looks good to me.
I am trying to follow this in the docs. I also looked into the code for the polyfill for 'closest' here.
Cause of error is that no valid div is referenced. When I use element[0] it starts working.
Furthermore scroll methods in the modal will only give value after modal properly opened, so need to use the #open event. See this for details.

Categories