Setup for Microsoft Teams Menus Module SDK is failing. setNavBarMenu() is not displaying the item in the navigation bar - sdk

Thanks for taking the time to review this matter.
So I've been going through this issue for a couple of days now. I'm trying to set up a navigation menu on my Microsoft Teams Side App. A set of personal tabs is exactly what it is. Following the documentation here: https://learn.microsoft.com/en-us/microsoftteams/platform/concepts/design/personal-apps?view=msteams-client-js-1.12.1#use-a-personal-app-private-workspace
It explicitly shows how we can add a navigation bar at the top-right of our application:
Screenshot from MSTeams documentation
Simple, right?
Well, it doesn't seem to work like that. When I try and follow the SDK instructions to set the navigation bar using the function microsoftTeams.menus.setNavBarMenu() it doesn't display anything nor provide any sort of error message on the console
This is the code I have set up for my Angular component:
import {Component, OnInit} from "#angular/core"
import {app, menus, pages} from "#microsoft/teams-js"
import {Location} from '#angular/common'
#Component({
selector: 'my-app',
templateUrl: './my-app.html',
styleUrls: ['./my-app.scss'],
})
export class MyApp implements OnInit {
public initialized = false
public theme = 'default'
constructor(private location: Location) { }
ngOnInit(): void {
app.initialize().then((response) => {
this.initialized = true
app.getContext().then((context) => {
if (context.app.theme !== 'default') {
this.theme = 'dark'
}
})
app.registerOnThemeChangeHandler((theme: string) => {
if (theme !== 'default') {
this.theme = 'dark'
} else {
this.theme = 'default'
}
})
pages.backStack.registerBackButtonHandler(() => {
this.location.back()
return true
})
menus.initialize()
const item = new menus.MenuItem()
item.id = 'test'
item.icon = 'there is an <svg></svg> tag here but I shortened it for easier reading'
item.title = 'test'
item.displayMode = menus.DisplayMode.ifRoom
console.log(item)
menus.setNavBarMenu([item], (id) => {
console.log(id)
return true
})
})
}
}
Nothing fancy. Just an HTML template with some styling that you can ignore. This is just a mock testing app. The only difference is that I import the namespace directly.
So, everything else is working: Microsoft Teams is being initialized, the theme handler sets a default or dark theme, and the back button works as indicated. The only thing that's missing is the navBarMenu.
I tried with and without an Icon value inside the string, with and without the displayMode property, I tried it directly on the HTML parent using a script tag, tried the previous SDK version (1.16) and this one (2.5)
I'm pretty sure I'm missing something on this setup, but I can't seem to find any information regarding this SDK menus module and the documentaion isn't really helpful there (Or maybe I'm not smart enough to get it, yet)
Again, thank you so much for reading me. Any feedback on anything I'm doing wrong or could potentially improve is completly welcome
Cheers!

Related

Angular CDK Overlay flexibleConnectedTo doesn't connect to origin

I would like to connect an angular cdk overlay to a button in my toolbar.
That's what I got:
overlay-button.html:
<button mat-menu-item #overlayButton (click)="showOverlay()"> open </button>
overlay-button.component
export class OverlayButtonComponent {
#ViewChild('overlayButton') private _button: ElementRef;
constructor(private _overlay: OverlayService) {}
showOverlay() {
this._overlay.open(DisplayedComponent,this._button);
}
}
overlay.service
export class OverlayService {
constructor(private _overlay: Overlay) {}
open(comp: ComponentType<any>, connectedTo:ElementRef) {
const positionStrategy = this._overlay.position()
.flexibleConnectedTo(connectedTo)
.withPositions([{
originX: 'start',
originY: 'bottom',
overlayX: 'start',
overlayY: 'top',
}]);
const overlayRef = this._overlay.create({
hasBackdrop: true,
positionStrategy,
scrollStrategy: this._overlay.scrollStrategies.reposition()
});
// Create ComponentPortal that can be attached to a PortalHost
const filePreviewPortal = new ComponentPortal(comp);
// Attach ComponentPortal to PortalHost
overlayRef.attach(filePreviewPortal);
overlayRef.backdropClick().subscribe(() => overlayRef.detach());
}
}
The problem is that the overlay is always displayed in the top left corner of the Browser.
First i thought there is a problem with the viewChild, maybe the elementRef is undefined or something like that, but that is not the case. I tried every tutorial I found with similar code and nothing worked. Could the problem be anywhere else?
Here is an illustration of how it is:
The reference you get from your ViewChild is not actually ElementRef. You can wrap the button to a div and then get ViewChild reference to that.
Based on #joonas comment, modify your viewChild Code to be
#ViewChild('overlayButton', {read: ElementRef}) private _button: ElementRef;
forcing the viewChild to be read as an ElementRef, and thereby passed into the flexibleConnectedTo() call.

MatFormField outline issue

When I change the font type in my form, label overlays the outline.
How can i fix this?
in the following image it is shown how it should be:
Seems like after 3 years there's still no fix to this issue in Angular Material.
However, there are two workarounds:
First workaround:
create a directive that links to all mat-form-field components (directives) with appearance attribute set to outline
listen to document.fonts.ready event and run updateOutlineGap on the MatFormField
export the directive in AppModule or SharedModule to make it accessible everywhere
this way Angular will update the outline size as soon as the custom font is loaded
import { AfterViewInit, Directive } from '#angular/core';
import { MatFormField } from '#angular/material/form-field';
#Directive({
selector: 'mat-form-field[appearance=outline]',
})
export class UpdateOutlineGapDirective implements AfterViewInit {
constructor(private formField: MatFormField) {
}
ngAfterViewInit() {
document.fonts.ready.then(() => {
this.formField.updateOutlineGap();
});
}
}
Second workaround:
add #userNameField to your mat-form-field element
add (focus)="userNameField.updateOutlineGap()" to the input element
this way every time the input is focused, Angular will update the outline size

Use DartAngular with dart:html

Is it possible to use default dart library html with angular dart?
ie:
class Test1Component implements OnInit{
#override
void ngOnInit() {
ButtonElement button = querySelector('button');
//Broken code, avoid button to be null.
button.onClick.listen(onClick);
}
void onClick(Event e){
print('Button clicked');
}
}
How can I avoid to get a 'null' button without the using any timers?
Basically I'm using only angular just for the Routes and but I'd like to stick with dart:html to control the DOM and events.
Yes, you can do that, but it's usually not a good idea.
Use instead #ViewChild(...) or similar Angular methods to get references to elements in a components view.
<button #myButton>click me</button>
#ViewChildren('myButton')
set myButton(List<Element> value) {
if(value.isNotEmpty) {
print(value.first);
}
}
If you want to just add a click handler using
<button (click)="onClick">click me</button>
would be the better way but it sounds you are somehow adding the button dynamically and adding a click handler declaratively might not work in this case (would need more info)
EDIT:
If someone like me want to use dart:html instead angular ng code, it's possible to use it
import 'package:angular/angular.dart';
import 'dart:html';
// AngularDart info: https://webdev.dartlang.org/angular
// Components info: https://webdev.dartlang.org/components
#Component(
selector: 'container',
template: '<h1>Test 1</h1><button #test1>Bottone test 1</button>',
)
class Test1Component implements OnInit{
#ViewChild('test1')
ButtonElement button;
#override
void ngOnInit() {
//Verified that button is initialized
print(button);
//Initialize click
button.onClick.listen((e) => print("Clicked"));
}
}

How can I disable check box that is part of Clarity datagrid?

I use Clarity datagrid and I need to disable the checkbox selection under some conditions. I can't find API to do so. Please help and thanks.
Disabling selection for specific rows of a datagrid is not available in Clarity yet, but there is a Contributions welcome issue open for it: https://github.com/vmware/clarity/issues/1018
I had similar requirement and ended up implementing the behavior using a custom directive.
have a look at:
https://plnkr.co/edit/5fQkvG?p=preview
#Directive({
selector: '[clrDisable]'
})
export class DisableDirective implements OnInit, OnChanges {
#Input('clrDisable') disabled:boolean
constructor(private elementRef:ElementRef) {
}
ngOnInit(){
}
ngOnChanges() {
let nativeRef = this.elementRef.nativeElement;
if(this.disabled) {
nativeRef.classList.add("clr_disabled");
} else {
nativeRef.classList.remove("clr_disabled");
}
}
}
.clr_disabled{
pointer-events:none;
background-color:#ccc;
opacity:0.5;
}

Protractor:Waiting for an element that is present but not displayed

I've written a test to check if a element is visible on screen, in my case an angular-ui-bootstrap collapsible panel, aka, the "warning". The code works, but the tests used to fail ~75% of the time.
There is a collapse animation on the display of the "warning", and I can't shutwod the animation for the tests, since it's a jquery animation. The warning is always 'present' in the DOM, just collapsed when there is no reason to show it.
At first, I've tested with this code, which is pretty easy:
expect(element('.warning').isDisplayed()).toEqual(true);
The problem came when I needed to test that the element is not displayed, e.g. : once the warning is displayed, some action cause it to collapse.
That test:
expect(element('.warning').isDisplayed()).toEqual(false);
will pass only if the animation started. It will fail when the condition is checked while the element is still displayed.
I've came up with two solutions.
The easy one using a ptor.driver.sleep(2000). Is slows my tests and is not acceptable.
The hard, ugly one, but that gives me good results:
exports.isWarningDisplayed = function (expectedVisibility) {
return ptor.driver.wait(function () {
if (expectedVisibility) {
return element(by.css('.warning')).isDisplayed().then(function(visibility) {
return visibility === expectedVisibility;
});
} else {
return element.all(by.css('.warning .collapse.in')).then(function(items) {
return items.length === 0;
});
}
}, 2000).then(function() {
return element.all(by.css('.warning .collapse.in'));
}).then(function (items) {
return items.length > 0;
});
};
My problem is that it just feels awfully wrong. Have you found a better way to handle that situation? My expectation would be to have something like:
expect(element('.warning').not.isDisplayed()).toEqual(true);
...but there is no .not in protractor or webDriver AFAIK.
I had a similar issue - wanting to test for when an element is no longer disabled. I struggled trying to work around things without the .not test and then realized that I could just move the 'not' test into the css selector:
// we're looking for when the element doesn't have a .disabled class
var availableElement = by.css('.some-class:not(.disabled)');
browser.wait(function() {
return ptor.isElementPresent(availableElement);
}, 30000);
expect(ptor.isElementPresent(availableElement)).toBeTruthy();
Not sure if it helps but I had a moment of clarity so thought I would share.
Using the elementexplorer (https://github.com/angular/protractor/blob/master/docs/debugging.md) I looked at the protractor object and found an answer that is working wonderfully for me:
var el = element(by.id('visibleElementId'));
browser.driver.wait(protractor.until.elementIsNotVisible(el));
expect(ptor.isElementPresent(by.css('.warning'))).toBe(false);
This is another way of checking if something is displayed on the page or not
From my experience, this is a common "sad" issue. You know your code is written properly, but test is failed due to waits. For instance, in Chrome I get the next error in console :
< unknown error: Element is not clickable at point (952, 275). >
So, I created separate function in my WebDriver class and seems it works:
this.waitElementToBeShown = function (elmLocator) {
browser.sleep(500);
browser.wait(function () {
return (elmLocator).isPresent();
}, 3000);
browser.wait(function () {
return (elmLocator).isDisplayed();
}, 3000);
}

Resources