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

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>

Related

Setting the Vue Component for a BlockGroup

I'm trying to build a custom component in Piranha called Table. It consists of a BlockGroup called TableBlock, which contains a BlockGroup called TableRowBlock, which itself contains a list of fields of type TableCellField.
I've never embedded a BlockGroup inside a BlockGroup before and not sure if it's possible, but I hope it is.
A BlockGroup by default is rendered by the block-group (or block-group-horizontal?) Vue component in the admin, but I want to render it with my own custom Vue component.
It seems like even though I set the Component property on the BlockGroup, it ignores it and it still defaults to one of the default components for a BlockGroup, such as block-group or block-group-horizontal.
Is there any way to accomplish what I'm trying to do?
namespace Piranha.Extend.Blocks
{
[BlockGroupType(Name = "Table", Category = "Content", Icon = "fas fa-images", Component = "table-block")]
[BlockItemType(Type = typeof(TableRowBlock))]
public class TableBlock : BlockGroup
{
}
[BlockGroupType(Name = "Table Row", Category = "Content", Icon = "fas fa-images", Component = "table-row-block")]
[BlockItemType(Type = typeof(TableCellField))]
public class TableRowBlock : BlockGroup
{
public int RowNumber { get; set; }
public override string GetTitle()
{
return "Row";
}
}
}
namespace Piranha.Extend.Fields
{
[FieldType(Name = "TableCell", Shorthand = "Text", Component = "table-cell-field")]
public class TableCellField : IField
{
public string Value { get; set; }
public int ColumnNumber { get; set; }
public string GetTitle()
{
return !string.IsNullOrEmpty(ColumnNumber.ToString()) ? ColumnNumber.ToString() : "";
}
}
}
Here's the "table-block" Vue component:
<template>
<div :id="uid" class="block-group">
<table>
<template v-for="child in model.items">
<component v-bind:is="child.meta.component" v-bind:uid="child.meta.uid" v-bind:toolbar="toolbar" v-bind:model="child.model"></component>
</template>
</table>
</div>
</template>
<script>
export default {
props: ["uid", "toolbar", "model"],
methods: {
},
mounted: function () {
}
}
</script>
Here's the "table-row-block" Vue component:
<template>
<tr :id="uid" class="block-group">
<template v-for="child in model.items">
<component v-bind:is="child.meta.component" v-bind:uid="child.meta.uid" v-bind:toolbar="toolbar" v-bind:model="child.model" v-on:update-title="updateTitle($event)"></component>
</template>
</tr>
</template>
<script>
export default {
props: ["uid", "toolbar", "model"],
methods: {
},
mounted: function () {
var self = this;
}
}
</script>
Here's the "table-cell-field" Vue component:
<template>
<td :id="uid">
<input class="form-control" :placeholder="meta.placeholder" v-model="model.value" v-on:change="update()" type="text" />
<input class="form-control" v-model="model.columnNumber" type="hidden" />
</td>
</template>
<script>
export default {
props: ["uid", "model", "meta"],
methods: {
update: function () {
}
}
}
</script>
Here's the error I'm getting:
Unfortunately none of the things you’re trying to do is currently supported, that means:
Block groups can’t contain other block groups, only blocks.
Block groups can’t have custom vue components, they use the selected built in rendering in the manager.
The second one would be easy to support, and could be added in a service release. The first one however couldn’t be added without serious redesign of the editor UI/UX since the built in model doesn’t support collections on multiple levels.
The best solution with the current data model is to simply add a global field to the Table block that specifies the number of columns. This could then be used when rendering the custom block group component if support was added to this.

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 access shadowFunction of element1 form shadowRoot of other element2 in polymer 2.0

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);
}

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.

Vuejs vue-nav-tabs change title of tabs [duplicate]

Let's say I have a main Vue instance that has child components. Is there a way of calling a method belonging to one of these components from outside the Vue instance entirely?
Here is an example:
var vm = new Vue({
el: '#app',
components: {
'my-component': {
template: '#my-template',
data: function() {
return {
count: 1,
};
},
methods: {
increaseCount: function() {
this.count++;
}
}
},
}
});
$('#external-button').click(function()
{
vm['my-component'].increaseCount(); // This doesn't work
});
<script src="http://vuejs.org/js/vue.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="app">
<my-component></my-component>
<br>
<button id="external-button">External Button</button>
</div>
<template id="my-template">
<div style="border: 1px solid; padding: 5px;">
<p>A counter: {{ count }}</p>
<button #click="increaseCount">Internal Button</button>
</div>
</template>
So when I click the internal button, the increaseCount() method is bound to its click event so it gets called. There is no way to bind the event to the external button, whose click event I am listening for with jQuery, so I'll need some other way to call increaseCount.
EDIT
It seems this works:
vm.$children[0].increaseCount();
However, this is not a good solution because I am referencing the component by its index in the children array, and with many components this is unlikely to stay constant and the code is less readable.
In the end I opted for using Vue's ref directive. This allows a component to be referenced from the parent for direct access.
E.g.
Have a component registered on my parent instance:
var vm = new Vue({
el: '#app',
components: { 'my-component': myComponent }
});
Render the component in template/html with a reference:
<my-component ref="foo"></my-component>
Now, elsewhere I can access the component externally
<script>
vm.$refs.foo.doSomething(); //assuming my component has a doSomething() method
</script>
See this fiddle for an example: https://jsfiddle.net/0zefx8o6/
(old example using Vue 1: https://jsfiddle.net/6v7y6msr/)
Edit for Vue3 - Composition API
The child-component has to return the function in setup you want to use in the parent-component otherwise the function is not available to the parent.
Note: <sript setup> doc is not affacted, because it provides all the functions and variables to the template by default.
You can set ref for child components then in parent can call via $refs:
Add ref to child component:
<my-component ref="childref"></my-component>
Add click event to parent:
<button id="external-button" #click="$refs.childref.increaseCount()">External Button</button>
var vm = new Vue({
el: '#app',
components: {
'my-component': {
template: '#my-template',
data: function() {
return {
count: 1,
};
},
methods: {
increaseCount: function() {
this.count++;
}
}
},
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<my-component ref="childref"></my-component>
<button id="external-button" #click="$refs.childref.increaseCount()">External Button</button>
</div>
<template id="my-template">
<div style="border: 1px solid; padding: 2px;" ref="childref">
<p>A counter: {{ count }}</p>
<button #click="increaseCount">Internal Button</button>
</div>
</template>
For Vue2 this applies:
var bus = new Vue()
// in component A's method
bus.$emit('id-selected', 1)
// in component B's created hook
bus.$on('id-selected', function (id) {
// ...
})
See here for the Vue docs.
And here is more detail on how to set up this event bus exactly.
If you'd like more info on when to use properties, events and/ or centralized state management see this article.
See below comment of Thomas regarding Vue 3.
You can use Vue event system
vm.$broadcast('event-name', args)
and
vm.$on('event-name', function())
Here is the fiddle:
http://jsfiddle.net/hfalucas/wc1gg5v4/59/
A slightly different (simpler) version of the accepted answer:
Have a component registered on the parent instance:
export default {
components: { 'my-component': myComponent }
}
Render the component in template/html with a reference:
<my-component ref="foo"></my-component>
Access the component method:
<script>
this.$refs.foo.doSomething();
</script>
Say you have a child_method() in the child component:
export default {
methods: {
child_method () {
console.log('I got clicked')
}
}
}
Now you want to execute the child_method from parent component:
<template>
<div>
<button #click="exec">Execute child component</button>
<child-cmp ref="child"></child_cmp> <!-- note the ref="child" here -->
</div>
</template>
export default {
methods: {
exec () { //accessing the child component instance through $refs
this.$refs.child.child_method() //execute the method belongs to the child component
}
}
}
If you want to execute a parent component method from child component:
this.$parent.name_of_method()
NOTE: It is not recommended to access the child and parent component like this.
Instead as best practice use Props & Events for parent-child communication.
If you want communication between components surely use vuex or event bus
Please read this very helpful article
This is a simple way to access a component's methods from other component
// This is external shared (reusable) component, so you can call its methods from other components
export default {
name: 'SharedBase',
methods: {
fetchLocalData: function(module, page){
// .....fetches some data
return { jsonData }
}
}
}
// This is your component where you can call SharedBased component's method(s)
import SharedBase from '[your path to component]';
var sections = [];
export default {
name: 'History',
created: function(){
this.sections = SharedBase.methods['fetchLocalData']('intro', 'history');
}
}
Using Vue 3:
const app = createApp({})
// register an options object
app.component('my-component', {
/* ... */
})
....
// retrieve a registered component
const MyComponent = app.component('my-component')
MyComponent.methods.greet();
https://v3.vuejs.org/api/application-api.html#component
Here is a simple one
this.$children[indexOfComponent].childsMethodName();
I am not sure is it the right way but this one works for me.
First import the component which contains the method you want to call in your component
import myComponent from './MyComponent'
and then call any method of MyCompenent
myComponent.methods.doSomething()
Declare your function in a component like this:
export default {
mounted () {
this.$root.$on('component1', () => {
// do your logic here :D
});
}
};
and call it from any page like this:
this.$root.$emit("component1");
If you're using Vue 3 with <script setup> sugar, note that internal bindings of a component are closed (not visible from outside the component) and you must use defineExpose(see docs) to make them visible from outside. Something like this:
<script setup lang="ts">
const method1 = () => { ... };
const method2 = () => { ... };
defineExpose({
method1,
method2,
});
</script>
Since
Components using are closed by default
Sometimes you want to keep these things contained within your component. Depending on DOM state (the elements you're listening on must exist in DOM when your Vue component is instantiated), you can listen to events on elements outside of your component from within your Vue component. Let's say there is an element outside of your component, and when the user clicks it, you want your component to respond.
In html you have:
Launch the component
...
<my-component></my-component>
In your Vue component:
methods() {
doSomething() {
// do something
}
},
created() {
document.getElementById('outsideLink').addEventListener('click', evt =>
{
this.doSomething();
});
}
I have used a very simple solution. I have included a HTML element, that calls the method, in my Vue Component that I select, using Vanilla JS, and I trigger click!
In the Vue Component, I have included something like the following:
<span data-id="btnReload" #click="fetchTaskList()"><i class="fa fa-refresh"></i></span>
That I use using Vanilla JS:
const btnReload = document.querySelector('[data-id="btnReload"]');
btnReload.click();