How to access shadowFunction of element1 form shadowRoot of other element2 in polymer 2.0 - polymer-2.x

This is my html structure,
//--this is index.html--//
<body>
<my-app></my-app>
</body>
//--this is my-app.html--//
<dom-module id="my-app">
<my-page1></my-page1>
<my-page2></my-page2>
</dom-module>
//--this is my-page1.html--//
<dom-module id="my-page1">
<script>
class MyPage1 extends Polymer.Element {
static get is() { return 'my-page1'; }
covert_data(){
alert("in covert_data");
}
}
window.customElements.define(MyPage1.is, MyPage1);
</script>
</dom-module>
//--this is my-page2.html--//
<dom-module id="my-page2">
<paper-button on-tap="addData">Save</paper-button>
<script>
class MyPage1 extends Polymer.Element {
static get is() { return 'my-page2'; }
addData(){
var host = document.querySelector('my-app').shadowRoot.querySelector('my-page1');
host.covert_data();
}
}
window.customElements.define(MyPage2.is, MyPage2);
</script>
</dom-module>
<my-page1></my-page1> has 1 method called covert_data(). I am trying below code.
way1:
var host = document.querySelector('my-app').shadowRoot.querySelector('my-page1');
host.covert_data();
This giving me error host.covert_data is not a function
way2:
document.querySelector('my-page1').covert_data();
This giving me error Cannot read property 'covert_data' of null
How to call that covert_data() method in <my-page2></my-page2> in
polymer 2.0

Before starting with the solution i would like to give you a tip.
Please make sure that you post a working piece of code.
It's been quite a few months since i worked Polymer and it took me 15-20 minutes just to get your code working. An in that 15-20 minutes i thought about leaving it lot of times.
Posting a working code will help people on community to help you better.
Now to solution
I found lot of issues in your code. I don't know which were because of writing incomplete code in SO and which genuine, so i'll point them all.
script tag and registration missing for my-app.
constructor and Super missing for all the elements.
template tag is missing for shadowDom.
I don't know why your way 1 is not working, it's working fine for me. I can only guess it might be because of missing constructor, but way 2 will not work and my-page1 is not present directly in document. It's part of shadowRoot of my-app.
Below is the working snippet of your code. I've changed on-tap to on-click to avoid importing gesture events files.
<script src="https://polygit.org/components/webcomponentsjs/webcomponents-loader.js"></script>
<link rel="import" href="https://polygit.org/components/polymer/polymer-element.html">
<!-- my-app element -->
<dom-module id="my-app">
<template>
<my-page1></my-page1>
<my-page2></my-page2>
</template>
<script>
class MyApp extends Polymer.Element {
static get is() {
return 'my-app'
}
constructor() {
super();
}
}
window.customElements.define(MyApp.is, MyApp);
</script>
</dom-module>
<!-- page1 element -->
<dom-module id="my-page1">
<script>
class MyPage1 extends Polymer.Element {
static get is() {
return 'my-page1';
}
constructor() {
super();
}
covert_data() {
alert("in covert_data");
}
}
window.customElements.define(MyPage1.is, MyPage1);
</script>
</dom-module>
<!-- page2 element -->
<dom-module id="my-page2">
<template> <div on-click="addData">Save</div></template>
<script>
class MyPage2 extends Polymer.Element {
static get is() {
return 'my-page2';
}
constructor() {
super();
}
addData() {
var host = document.querySelector('my-app').shadowRoot.querySelector('my-page1');
host.covert_data();
}
}
window.customElements.define(MyPage2.is, MyPage2);
</script>
</dom-module>
<!-- calling element -->
<my-app></my-app>

In page1.html :
this.dispatchEvent(new CustomEvent('upway-func', {detail: {op:"Optionally I can send some data"}}));
In myApp.html define id to child element in order to call a function and on-upway-func event :
<my-app>
<page1 on-upway-func="callPage2Func"></page1>
<page2 id="child2"></page2>
</my-app>
...
callPage2Func(op){
console.log(op)//Optionally I can send some data
this.$.child2.covert_data(op);
}

Related

Intellij Vue project change indentation level after <script> tags

So I work in a team that predominantly uses VSCode for the front-end work, I use Intellij myself as that's what I'm comfortable with. Issue is that when I go to format the code using Intellij it adds an initial indent to the code within <script> and <style> tags, it's not the worlds biggest issue - just a bit of a pain in the arse.
Their code would look like this:
<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
#Component
export default class CollapsibleSection extends Vue {
#Prop() public index: any;
#Prop() public value: any;
public isActive() {
return this.index === this.value;
}
}
</script>
My code would look like this:
<script lang="ts">
import {Component, Prop, Vue} from 'vue-property-decorator';
#Component
export default class CollapsibleSection extends Vue {
#Prop() public index: any;
#Prop() public value: any;
public isActive() {
return this.index === this.value;
}
}
</script>
This will be fixed in the next major release, 2020.2, see WEB-30382.
For now, please try adding both script and style to the list of Do not indent children of in Settings | Editor | Code Style | HTML | Other

Is it possible to pass data from Polymer component to Vue component?

The below code is what I'd like to do but it currently doesn't work. I'm trying to start building Vue components inside my Polymer app as a way to slowly migrate off Polymer.
I've been able to get a Vue component working inside my Polymer app, but I'm stuck on how to pass data from the Polymer component to the Vue component. Ideally, what I'd like to do is pass a Polymer property into the Vue component like I'm doing with testValue below (although the code below doesn't work)
Any pointers are greatly appreciated, thank you!
<dom-module id="part-input-view">
<template>
<style include="part-input-view-styles"></style>
<div id="vueApp">
<vue-comp id="test" test$="[[testValue]]"></vue-comp>
</div>
</template>
<script>
class PartInputView extends Polymer.Element {
static get is() { return 'part-input-view'; }
constructor() {
super();
}
static get properties() {
return {
testValue: 'This is working!'
};
}
ready() {
super.ready();
Vue.component('vue-comp', {
props: ['test'],
template: '<div class="vue-comp">{{test}}</div>'
})
const el = this.shadowRoot.querySelector('#vueApp')
let vueApp = new Vue({
el
});
}
}
</script>
</dom-module>
Yes, it's possible. Your code would've worked had it not been for your [incorrect] property declaration. You should see this error in the console:
element-mixin.html:122 Uncaught TypeError: Cannot use 'in' operator to search for 'value' in This is working!
at propertyDefaults (element-mixin.html:122)
at HTMLElement._initializeProperties (element-mixin.html:565)
at new PropertiesChanged (properties-changed.html:175)
at new PropertyAccessors (property-accessors.html:120)
at new TemplateStamp (template-stamp.html:126)
at new PropertyEffects (property-effects.html:1199)
at new PropertiesMixin (properties-mixin.html:120)
at new PolymerElement (element-mixin.html:517)
at new PartInputView (part-input-view.html:17)
at HTMLElement._stampTemplate (template-stamp.html:473)
In Polymer, string properties with a default value can only be declared like this:
static get properties() {
return {
NAME: {
type: String,
value: 'My default value'
}
}
}
There is no shorthand for this. You might've confused the shorthand for the uninitialized property, which would be:
static get properties() {
return {
NAME: String
}
}
If you fix that bug, you'll notice your code works...
class PartInputView extends Polymer.Element {
static get is() { return 'part-input-view'; }
static get properties() {
return {
testValue: {
type: String,
value: 'This is working!'
}
};
}
ready() {
super.ready();
Vue.component('vue-comp', {
props: ['test'],
template: '<div class="vue-comp">{{test}}</div>'
})
const el = this.shadowRoot.querySelector('#vueApp')
let vueApp = new Vue({
el
});
}
}
customElements.define(PartInputView.is, PartInputView)
<head>
<script src="https://unpkg.com/vue#2.6.10"></script>
<base href="https://cdn.rawgit.com/download/polymer-cdn/2.6.0.2/lib/">
<script src="webcomponentsjs/webcomponents-loader.js"></script>
<link rel="import" href="polymer/polymer.html">
</head>
<body>
<part-input-view></part-input-view>
<dom-module id="part-input-view">
<template>
<style include="part-input-view-styles"></style>
<div id="vueApp">
<vue-comp id="test" test$="[[testValue]]"></vue-comp>
</div>
</template>
</dom-module>
</body>

How to call a function in polymer 2.0 on button onclick or anchor tag click?

I am seeing functionality like Compute function where i can use a function to compute same thing and then retrun something to that textcontent area but how to use them on button onclick or anchor onclick .
for example :
<dom-module id="x-custom">
<template>
My name is <span>[[_formatName(first, last)]]</span>
</template>
<script>
class XCustom extends Polymer.Element {
static get is() {return 'x-custom'}
static get properties() {
return {
first: String,
last: String
}
}
_formatName(first, last) {
return `${last}, ${first}`;
}
}
customElements.define(XCustom.is, XCustom);
</script>
</dom-module>
In this case the _formatName is manipulated in and we get resultant in html.
But how to to in button onclick and
So that i can manipulate for send some http request .
Also manipulate some data inside the function .
Polymer 2.0
I got the answer . First of all for two way binding you also check the polymer 1.0 doc for data binding that is in brief .
And then you can read polymer 2.0 doc but i don't see more for data binding event there.
I will say read both.
https://www.polymer-project.org/1.0/docs/devguide/templates
https://www.polymer-project.org/2.0/docs/devguide/templates
This have example for custom event .
https://www.polymer-project.org/2.0/docs/devguide/events.html#custom-events
<dom-module id="x-custom">
<template>
<button on-click="handleClick">Kick Me</button>
</template>
<script>
class XCustom extends Polymer.Element {
static get is() {return 'x-custom'}
handleClick() {
console.log('Ow!');
}
}
customElements.define(XCustom.is, XCustom);
</script>
</dom-module>
Also if you want argument to pass to the function you can do this.
<dom-module id="x-custom">
<template>
<button on-click="handleClick" data-args="arg1,arg2">Kick Me</button>
</template>
<script>
class XCustom extends Polymer.Element {
static get is() {return 'x-custom'}
handleClick(e) {
console.log('Ow!');
console.log(e.target.getAttribute('data-args'));
// now you got args you can use them as you want
}
}
customElements.define(XCustom.is, XCustom);
</script>
</dom-module>

How to extend Polymer.AppNetworkStatusBehavior into custom Mixin in Polymer2?

In Polymer 1.0, I have the following code snippet:-
CustomBehaviorImpl = {
properties: {
// Define property here...
// ...
},
// Other custom behaviors definition
// ...
};
CustomBehavior = [
Polymer.AppNetworkStatusBehavior,
CustomBehaviorImpl,
];
How would I do it in Polymer 2.0 to create a CustomMixin class.
If you separate the mixins into its own file you can reference them as an Html Import dependency whenever composing an element that uses mixins.
Just extend your Polymer class with your custom behaviours.
I think this question has been answered already here on stackoverflow.
Take a look at this one:
Applying Behaviors with JS Mixins in Polymer 2
Example
This is my CustomMixin.html
<script>
// CustomMixin provides the _customMixin function
var CustomMixin = function(superClass) {
return class extends superClass {
_customMixin() {
}
}
}
</script>
This is my Polymer Element where I make use of the CustomMixin.
<link rel="import" href="../../bower_components/polymer/polymer-element.html">
<link rel="import" href="../CustomMixin/CustomMixin.html">
<dom-module id="my-element">
<template>
<style>
:host {
display: block;
}
</style>
</template>
<script>
class MyElement extends CustomMixin(Polymer.Element) {
static get is() { return 'my-element'; }
static get properties() {
return {
};
}
ready() {
super.ready();
}
}
window.customElements.define(MyElement.is, MyElement);
</script>
</dom-module>
I actually never tested that code but I believe this should be the way to implement a custom mixin.

Angular 2 equivalent of ng-bind-html, $sce.trustAsHTML(), and $compile?

In Angular 1.x, we could insert HTML in real-time by using the HTML tag ng-bind-html, combined with the JavaScript call $sce.trustAsHTML(). This got us 80% of th way there, but wouldn't work when Angular tags were used, such as if you inserted HTML that used ng-repeat or custom directives.
To get that to work, we could use a custom directive that called $compile.
What is the equivalent for all of this in Angular 2? We can bind using [inner-html] but this only works for very simple HTML tags such as <b>. It doesn't transform custom angular 2 directives into functioning HTML elements. (Much like Angular 1.x without the $compile step.) What is the equivalent of $compile for Angular 2?
In Angular2 you should use DynamicComponentLoader to insert some "compiled content" on the page. So for example if you want to compile next html:
<div>
<p>Common HTML tag</p>
<angular2-component>Some angular2 component</angular2-component>
</div>
then you need to create component with this html as a template (let's call it CompiledComponent) and use DynamicComponentLoader to insert this component on the page.
#Component({
selector: 'compiled-component'
})
#View({
directives: [Angular2Component],
template: `
<div>
<p>Common HTML tag</p>
<angular2-component>Angular 2 component</angular2-component>
</div>
`
})
class CompiledComponent {
}
#Component({
selector: 'app'
})
#View({
template: `
<h2>Before container</h2>
<div #container></div>
<h2>After conainer</h2>
`
})
class App {
constructor(loader: DynamicComponentLoader, elementRef: ElementRef) {
loader.loadIntoLocation(CompiledComponent, elementRef, 'container');
}
}
Check out this plunker
UPD You can create component dynamically right before the loader.loadIntoLocation() call:
// ... annotations
class App {
constructor(loader: DynamicComponentLoader, elementRef: ElementRef) {
// template generation
const generatedTemplate = `<b>${Math.random()}</b>`;
#Component({ selector: 'compiled-component' })
#View({ template: generatedTemplate })
class CompiledComponent {};
loader.loadIntoLocation(CompiledComponent, elementRef, 'container');
}
}
I personally don't like it, it's look like a dirty hack to me. But here is the plunker
PS Beware that at this moment angular2 is under active development. So situation can be changed at any time.
DynamicComponentLoader is deprecated, you can use ComponentResolver instead
You could use this directive, add pipes if you need additional data manipulation. It also allows for lazy loading, you don't need it in your case, but it's worth mentioning.
Directive(I found this code and made some changes, you can do that too to make it fit your taste or use it as is):
import { Component, Directive, ComponentFactory, ComponentMetadata, ComponentResolver, Input, ReflectiveInjector, ViewContainerRef } from '#angular/core';
declare var $:any;
export function createComponentFactory(resolver: ComponentResolver, metadata: ComponentMetadata): Promise<ComponentFactory<any>> {
const cmpClass = class DynamicComponent {};
const decoratedCmp = Component(metadata)(cmpClass);
return resolver.resolveComponent(decoratedCmp);
}
#Directive({
selector: 'dynamic-html-outlet',
})
export class DynamicHTMLOutlet {
#Input() htmlPath: string;
#Input() cssPath: string;
constructor(private vcRef: ViewContainerRef, private resolver: ComponentResolver) {
}
ngOnChanges() {
if (!this.htmlPath) return;
$('dynamic-html') && $('dynamic-html').remove();
const metadata = new ComponentMetadata({
selector: 'dynamic-html',
templateUrl: this.htmlPath +'.html',
styleUrls: [this.cssPath]
});
createComponentFactory(this.resolver, metadata)
.then(factory => {
const injector = ReflectiveInjector.fromResolvedProviders([], this.vcRef.parentInjector);
this.vcRef.createComponent(factory, 0, injector, []);
});
}
}
Example how to use it:
import { Component, OnInit } from '#angular/core';
import { DynamicHTMLOutlet } from './../../directives/dynamic-html-outlet/dynamicHtmlOutlet.directive';
#Component({
selector: 'lib-home',
templateUrl: './app/content/home/home.component.html',
directives: [DynamicHTMLOutlet]
})
export class HomeComponent implements OnInit{
html: string;
css: string;
constructor() {}
ngOnInit(){
this.html = './app/content/home/home.someTemplate.html';
this.css = './app/content/home/home.component.css';
}
}
home.component.html:
<dynamic-html-outlet [htmlPath]="html" [cssPath]="css"></dynamic-html-outlet>
After reading a lot, and being close of opening a new topic I decided to answer here just to try to help to others. As I've seen there are several changes with the latest version of Angular 2. (Currently Beta9)
I'll try to share my code in order to avoid the same frustration I had...
First, in our index.html
As usual, we should have something like this:
<html>
****
<body>
<my-app>Loading...</my-app>
</body>
</html>
AppComponent (using innerHTML)
With this property you will be able to render the basic HTML, but you won't be able to do something similar to Angular 1.x as $compile through a scope:
import {Component} from 'angular2/core';
#Component({
selector: 'my-app',
template: `
<h1>Hello my Interpolated: {{title}}!</h1>
<h1 [textContent]="'Hello my Property bound: '+title+'!'"></h1>
<div [innerHTML]="htmlExample"></div>
`,
})
export class AppComponent {
public title = 'Angular 2 app';
public htmlExample = ' <div>' +
'<span [textContent]="\'Hello my Property bound: \'+title"></span>' +
'<span>Hello my Interpolated: {{title}}</span>' +
'</div>'
}
This will render the following:
Hello my Interpolated: Angular 2 app!
Hello my Property bound: Angular 2 app!
Hello my Interpolated: {{title}}
AppComponent Using DynamicComponentLoader
There is a little bug with the docs, documented in here. So if we have in mind that, my code should look now like this:
import {DynamicComponentLoader, Injector, Component, ElementRef, OnInit} from "angular2/core";
#Component({
selector: 'child-component',
template: `
<div>
<h2 [textContent]="'Hello my Property bound: '+title"></h2>
<h2>Hello my Interpolated: {{title}}</h2>
</div>
`
})
class ChildComponent {
title = 'ChildComponent title';
}
#Component({
selector: 'my-app',
template: `
<h1>Hello my Interpolated: {{title}}!</h1>
<h1 [textContent]="'Hello my Property bound: '+title+'!'"></h1>
<div #child></div>
<h1>End of parent: {{endTitle}}</h1>
`,
})
export class AppComponent implements OnInit{
public title = 'Angular 2 app';
public endTitle= 'Bye bye!';
constructor(private dynamicComponentLoader:DynamicComponentLoader, private elementRef: ElementRef) {
// dynamicComponentLoader.loadIntoLocation(ChildComponent, elementRef, 'child');
}
ngOnInit():any {
this.dynamicComponentLoader.loadIntoLocation(ChildComponent, this.elementRef, 'child');
}
}
This will render the following:
Hello my Interpolated: Angular 2 app!
Hello my Property bound: Angular 2 app!
Hello my Property bound: ChildComponent title
Hello my Interpolated: ChildComponent title
End of parent: Bye bye!
I think all you have to do is set the element you want to have compiled html with the [innerHTML]="yourcomponentscopevar"
Angular provided DynamicComponentLoader class for loading html dynamically. DynamicComponentLoader have methods for inserting components. loadIntoLocation is one of them for inserting component.
paper.component.ts
import {Component,DynamicComponentLoader,ElementRef,Inject,OnInit} from 'angular2/core';
import { BulletinComponent } from './bulletin.component';
#Component({
selector: 'paper',
templateUrl: 'app/views/paper.html'
}
})
export class PaperComponent {
constructor(private dynamicComponentLoader:DynamicComponentLoader, private elementRef: ElementRef) {
}
ngOnInit(){
this.dynamicComponentLoader.loadIntoLocation(BulletinComponent, this.elementRef,'child');
}
}
bulletin.component.ts
import {Component} from 'angular2/core';
#Component({
selector: 'bulletin',
templateUrl: 'app/views/bulletin.html'
}
})
export class BulletinComponent {}
paper.html
<div>
<div #child></div>
</div>
Few things you need to take care of :
Don't call loadIntoLocation inside the constructor of class . Component view is not yet created when component constructor is called. You will get error -
Error during instantiation of AppComponent!. There is no component
directive at element [object Object]
Put anchorName #child in html otherwise you will get error.
Could not find variable child
Have a look at this module https://www.npmjs.com/package/ngx-dynamic-template
After a long research, only this thing helped me. The rest of the solutions seems to be outdated.