I use polymerfire authentication in a parent class. After successful authentication I wish to access the email attribute in a subclass.
Problem: the authentication information is not available in the subclass.
I use polymer 2.2.0.
Here is the parent class:
<link rel="import" href="../bower_components/polymer/polymer-element.html">
<link rel="import" href="../bower_components/polymerfire/polymerfire.html">
<link rel="import" href="../bower_components/paper-button/paper-button.html">
<link rel="import" href="shared-styles.html">
<dom-module id="my-loginparent">
<template>
<style include="shared-styles">
:host { display: block; padding: 10px; }
</style>
<firebase-app
auth-domain="....firebaseapp.com"
database-url="....firebaseio.com/"
api-key="..."
storage-bucket="....."
messaging-sender-id=".."
project-id="..">
</firebase-app>
<firebase-auth
id="auth"
user="{{user}}"
provider="google"
signed-in="{{signedIn}}"
status-known="{{statusKnown}}"
on-error="showError">
</firebase-auth>
<div class="card">
<div hidden$="[[user]]">
<h1>Login: Please select a login method</h1>
<div class="error" hidden$="[[!error]]">[[error.code]]: [[error.message]]</div>
<h3>b) Login with Google</h3>
<p>
<paper-button raised class="green" on-tap="mrLoginGoogle">Sign in with Google</paper-button>
</p>
</div>
</div>
</template>
<script type="text/javascript">
class MyLoginparent extends Polymer.Element {
static get is() { return 'my-loginparent'; }
static get properties() {
return {
user: { type: Object },
loggedin: { type: String, value: 'no'}
};
}
mrLoginGoogle() {
this.error = null;
this.authe = null;
this.$.auth.signInWithPopup()
.then(function (result) {
console.log('loginparent -> auth success: ' + result.user.email); // Works
})
.catch(function (error) {
console.log('loginparent -> auth fail: ' + error.code + "; " + error.message);
});
}
}
window.customElements.define(MyLoginparent.is, MyLoginparent);
Here is the childclass / subclass:
<link rel="import" href="my-loginparent.html">
<link rel="import" href="shared-styles.html">
<link rel="import" href="../bower_components/app-route/app-location.html">
<link rel="import" href="../bower_components/app-route/app-route.html">
<dom-module id="my-edt">
<template>
<style include="shared-styles">
:host { display: block; padding: 10px; }
</style>
<my-loginparent></my-loginparent>
<app-location route="{{route}}"></app-location>
<app-route route="{{route}}" pattern="/edt/:eid" data="{{routeData}}">
</app-route>
<h2>User: [[user.email]]</h2>
</template>
<script>
class MyEdt extends MyLoginparent {
static get is() { return 'my-edt'; }
constructor() {
super();
}
ready() {
super.ready();
console.log("my-edt: ready: " + JSON.stringify(this.user) ); // result: undefined
console.log("my-edt: super-ready loggedin: " + this.loggedin); // no --> okay
}
}
window.customElements.define(MyEdt.is, MyEdt);
</script>
</dom-module>
The authentication in the parent class works.
In the child class the console.log shows "undefined" and no value in h2 user.email is shown.
What needs to be changed to get this work?
Demo: https://www.41max.com/edt
The console.log in my-edt shows undefined because it's called on ready, before the user is able to press the button and add the credentials...
I see other things:
Are you aware of the Firebase error msg?
Firebase: Firebase App named '[DEFAULT]' already exists
(app/duplicate-app)
In my-edt you forgot to import app-location and app-route
Related
I'm using QUASAR and I want to get the state of my q-checkbox whether if it's checked or not. I've used event.target.checked and event.target.value but they are all undefined.
my checkbox:
<q-checkbox
v-on:click="addServices(full_service, $event)"
v-model="form.selected_full_services"
:val="full_service" />
my method:
addServices(full_service, event) {
console.log(event.target.checked)
console.log(event.target.value)
}
console:
output undefined
If I understood you correctly, maybe you don't need function at all :
const { ref } = Vue
const app = Vue.createApp({
setup () {
const full_services = ref( ['aaa', 'bbb', 'ccc'] )
const form = ref( { selected_full_services: [] } )
return { form, full_services }
}
})
app.use(Quasar)
app.mount('#q-app')
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons" rel="stylesheet" type="text/css">
<link href="https://cdn.jsdelivr.net/npm/quasar#2.10.1/dist/quasar.prod.css" rel="stylesheet" type="text/css">
<div id="q-app">
{{form}}
<div v-for="full_service in full_services">
<q-checkbox
:label="full_service"
v-model="form.selected_full_services"
:val="full_service" />
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#3/dist/vue.global.prod.js"></script>
<script src="https://cdn.jsdelivr.net/npm/quasar#2.10.1/dist/quasar.umd.prod.js"></script>
I am trying to initiate a function from methods while an input is keyup, But it's not working. My codes from template are :
<q-input type="number" min="1" dense borderless debounce="300" class="q-ma-xs" v-
model="invoice_product.item_qty" placeholder="quantity" filled
#keyup="calculateLineTotal(invoice_product)" />
My method :
<script>
export default {
setup() {
return {
invoice_product: {
item_qty: ''
}
}
},
methods: {
calculateLineTotal(invoice_product) {
alert(invoice_product.item_qty)
}
}
}
</script>
I also tried with v-on:keyup
enter code hereYou can use watch property using your v model variable and there you can write your logic.
When your model value change it will called watch property
watch:{
“Variable” : function(val) {
//method
}
}
Try to replace setup with data:
new Vue({
el: '#q-app',
data() {
return {
invoice_product: {item_qty: ''}
}
},
methods: {
calculateLineTotal(invoice_product) {
alert(invoice_product.item_qty)
}
},
})
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons" rel="stylesheet" type="text/css">
<link href="https://cdn.jsdelivr.net/npm/quasar#1.19.5/dist/quasar.min.css" rel="stylesheet" type="text/css">
<div id="q-app">
<q-input type="number" min="1" dense borderless debounce="300" class="q-ma-xs" v-
model="invoice_product.item_qty" placeholder="quantity" filled
#keyup="calculateLineTotal(invoice_product)" />
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#^2.0.0/dist/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/quasar#1.19.5/dist/quasar.umd.min.js"></script>
I am brand new to using VueJs (first day!)
I want to validate an email field, and return focus to the email inut if not valid. I am using the watch property (see below), and although I can successfully watch value changes, I am not able to set focus back to the email field.
What am I doing wrong?
Code snippet
<!DOCTYPE html>
<head>
<title>V3 Example</title>
<script src="https://unpkg.com/vue#3"></script>
</head>
<style type="text/css">
form input, form button {
display: block;
margin: 3px;
}
</style>
<body>
<div id="app">
<form #submit.prevent >
<h3></h3>
<input type="username" v-model="username" />
<input ref="email" type="email" v-model="email" />
<input type="password" v-model="passwd" autocomplete="off"/>
<button #click="logIt" >Login </button>
</form>
</div>
<script>
let app = Vue.createApp({
data() {
return {
username: '',
email: '',
passwd: '',
}
},
methods: {
logIt() {
console.log('here!');
}
},
watch: {
email(val1, val2){
if (!val2.includes('#')) {
this.$refs.email.focus(); // <- this is supposed to return focus to email input
console.log('Not valid email!');
}
else {
console.log(val1);
console.log(val2);
}
}
}
})
app.mount('#app');
</script>
</body>
</html>
Try this:
this.$refs.email.$el.focus();
Here is a solution that works, I've added a method onSubmit which is called when the form submits and inside it I validate email field, and focus it if is not valid. The key here is nextTick which makes sure to wait before Vue does any DOM update it needs before focusing the element.
<!DOCTYPE html>
<head>
<title>V3 Example</title>
<script src="https://unpkg.com/vue#3"></script>
</head>
<style type="text/css">
form input, form button {
display: block;
margin: 3px;
}
</style>
<body>
<div id="app">
<form #submit.prevent="onSubmit" >
<h3></h3>
<input type="username" v-model="username" />
<input ref="email" type="email" v-model="email" />
<input type="password" v-model="passwd" autocomplete="off"/>
<button #click="logIt" >Login </button>
</form>
</div>
<script>
let app = Vue.createApp({
data() {
return {
username: '',
email: '',
passwd: '',
}
},
methods: {
logIt() {
console.log('here!');
},
onSubmit() {
if (!this.email.includes('#')) {
this.$nextTick(() => { // must wait for next tick before interacting with DOM
this.$refs.email.focus();
console.log('Not valid email!');
})
}
}
},
watch: {
email(val1, val2){
if (!val2.includes('#')) {
this.$refs.email.focus(); // <- this is supposed to return focus to email input
console.log('Not valid email!');
}
else {
console.log(val1);
console.log(val2);
}
}
}
})
app.mount('#app');
</script>
</body>
I am working on a site where the user can select an image via radio selection.
I would like to dynamically update the image URL depending on selection of the user. My approach is to use a computed variable which returns the URL from a list of objects depending on the selection of the user.
<template>
<v-img
:src="require(currBackgroundURL)"
class="my-3"
contain
width="397"
height="560"
></v-img>
</template>
<script>
// data() ...
currBackground: 0,
backgrounds: [
{
name: "Flowers",
url: "../assets/background/bg_1.png"
},
// ...
computed: {
currBackgroundURL: function() {
return this.backgrounds[this.currBackground].url
}
}
</script>
Unfortunately, i get an error which says Critical dependency: the request of a dependency is an expression.
And the browser console says: [Vue warn]: Error in render: "Error: Cannot find module '../assets/background/bg_1.png'"
Question: What is the right way to switch the URL of the image dynamically?
Thanks for your help!
Here is a working example:
var app = new Vue({
el: '#app',
data: () => ({
currBackground: 0,
backgrounds: [
{
name: "black",
url: "https://dummyimage.com/600x400/000/fff"
},
{
name: "blue",
url: "https://dummyimage.com/600x400/00f/fff"
},
{
name: "red",
url: "https://dummyimage.com/600x400/f00/fff"
}
]
}),
computed: {
currBackgroundURL: function() {
return this.backgrounds[this.currBackground].url
}
},
methods: {
nextImage() {
this.currBackground += 1
if (this.currBackground > 2) {
this.currBackground = 0
}
}
}
})
<html>
<head>
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.min.css" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.18/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.js"></script>
<div id="app">
<v-btn #click="nextImage()">Change image</v-btn>
<v-img
:src="currBackgroundURL"
class="my-3"
contain
width="397"
height="560"
></v-img>
</div>
</body>
I removed the require.
The src is a link/path so you don't need require. require will try to take a path and load it into a module instead of a link/path.
Hopefully, this helps.
Hi I am having some trouble getting a menu to add options dynamically. They idea is the selection of the first menu decides what the second menu contains. I have built this before successfully without polymer. And it semi-works with polymer. dropdown one gets its content from json based on the selection, dropdown two gets its content also from a json. This part works, the issue is when you make a selection from dropdown one and then change it, dropdown two doesn't delete the old selection. I got this working last time with a function that first deletes all dropdown two's children before repopulating the content. Issue with Polymer is once the childNodes are deleted the dropdown breaks and no other children can be added via data binding. tried adding native with plain JS which populates the menu but the children are not selectable(from what I have read this might be a bug). Also I believe data binding on dynamic items also doesnt work anymore. anyway here is what I have:
<link rel="import" href="../../../bower_components/polymer/polymer.html">
<link rel="import" href="../../../bower_components/paper-material/paper-material.html">
<link rel="import" href="../../../bower_components/paper-dropdown-menu/paper-dropdown-menu.html">
<link rel="import" href="../../../bower_components/paper-menu/paper-menu.html">
<link rel="import" href="../../../bower_components/paper-item/paper-item.html">
<link rel="import" href="../../../bower_components/iron-ajax/iron-ajax.html">
<link rel="import" href="../../../bower_components/paper-button/paper-button.html">
<link rel="import" href="../../../bower_components/iron-dropdown/demo/x-select.html">
<dom-module id="add-skill">
<template>
<paper-material elevation="1">
<paper-dropdown-menu id="ddMenu" attr-for-selected="value" >
<paper-menu class="dropdown-content" id="vendorSelect" on-iron-select="_itemSelected">
<template is="dom-repeat" items="{{vendorList}}">
<paper-item id="vendorName" value="item">[[item]]</paper-item>
</template>
</paper-menu>
</paper-dropdown-menu>
<paper-dropdown-menu>
<paper-menu class="dropdown-content" id="certificationSelect" on-iron-select="_itemSelected">
</paper-menu>
</paper-dropdown-menu>
<!-- testing ideas -->
<paper-dropdown-menu>
<paper-menu class="dropdown-content" id="test" on-iron-select="_itemSelected">
<option extends="paper-item"> Option </option>
<option extends="paper-item"> Option1 </option>
<option extends="paper-item"> Option2 </option>
</paper-menu>
</paper-dropdown-menu>
<paper-button on-click="_deleteElement">
Delete
</paper-button>
</paper-material>
<iron-ajax
id="vendorSubmit"
method="POST"
url="../../../addskill.php"
handle-as="json"
on-response="handleVendorResponse"
debounce-duration="300">
</iron-ajax>
<iron-ajax
id="certificationSubmit"
method="POST"
url="../../../addskill.php"
handle-as="json"
on-response="handleCertificationResponse"
debounce-duration="300">
</iron-ajax>
</template>
<script>
Polymer({
is: 'add-skill',
ready: function() {
this.sendVendorRequest();
this.vendorList = [];
this.certificationList = [];
},
sendVendorRequest: function() {
var datalist = 'vendor=' + encodeURIComponent('1');
//console.log('datalist: '+datalist);
this.$.vendorSubmit.body = datalist;
this.$.vendorSubmit.generateRequest();
},
handleVendorResponse: function(request) {
var response = request.detail.response;
for (var i = 0; i < response.length; i++) {
this.push('vendorList', response[i].name);
}
},
vendorClick: function() {
var item = this.$;
//var itemx = this.$.vendorSelect.selectedItem.innerHTML;
//console.log(item);
//console.log(itemx);
},
sendCertificationRequest: function(vendor) {
var datalist = 'vendorName=' + encodeURIComponent(vendor);
console.log('datalist: ' + datalist);
this.$.certificationSubmit.body = datalist;
this.$.certificationSubmit.generateRequest();
},
handleCertificationResponse: function(request) {
var response = request.detail.response;
//var vendorSelect = document.getElementById('vendorSelect');
for (var i = 0; i < response.length; i++) {
this.push('certificationList', response[i].name);
}
console.log(this.certificationList);
},
_itemSelected: function(e) {
var selectedItem = e.target.selectedItem;
if (selectedItem) {
this.sendCertificationRequest(selectedItem.innerText);
console.log("selected: " + selectedItem.innerText);
}
},
_removeArray: function(arr) {
this.$.certificationList.remove();
for (var i = 0; i < arr.length; i++) {
console.log(arr[i]);
arr.splice(0, i);
arr.pop();
}
console.log(arr.length);
},
_deleteElement: function() {
var element = document.getElementById('certificationSelect');
while (element.firstChild) {
element.removeChild(element.firstChild);
}
},
_createElement: function() {
var doc = document.querySelector('#test');
var option = document.createElement('option');
option.extends = "paper-item";
option.innerHTML = "Option";
doc.appendChild(option);
}
});
</script>
</dom-module>
Any guidance is always appreciated
Here's a working version of your JSBin, which uses data binding and a <template is="dom-repeat"> to create new, selectable <paper-item> elements dynamically.
I'm not sure what specific issues you ran into when using data binding to stamp out the <paper-item> elements, but the important thing to remember in Polymer 1.0 is that when you modify an Array (or an Object) that is bound to a template, you need to use the new helper methods (like this.push('arrayName', newItem)) to ensure the bindings are updated.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<base href="http://element-party.xyz">
<script src="bower_components/webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="all-elements.html">
</head>
<body>
<dom-module id="x-module">
<template>
<paper-material elevation="1">
<paper-dropdown-menu>
<paper-menu class="dropdown-content" on-iron-select="_itemSelected">
<template is="dom-repeat" items="[[_menuItems]]">
<paper-item>[[item]]</paper-item>
</template>
</paper-menu>
</paper-dropdown-menu>
<paper-button on-click="_createItem">Add</paper-button>
</paper-material>
</template>
<script>
Polymer({
_createItem: function() {
this.push('_menuItems', 'New Option ' + this._menuItems.length);
},
_itemSelected: function() {
console.log('Selected!');
},
ready: function() {
this._menuItems = ['First Initial Option', 'Second Initial Option'];
}
});
</script>
</dom-module>
<x-module></x-module>
</body>
</html>