Referencing values within Polymer elements - polymer

I'm following the codelab for Polymerfire and first bit of tinkering, wanted to change the login element from using google sign in to use email / password.
The element works but I've been having trouble trying to access the values of the email / password field outside of the element itself.
I would've thought that I could access the value of the email textfield by referencing this.$.login.email.value but that doesn't work.
Here's my code
The login element
<dom-module id="as-login">
<template>
<!-- Here we stick in our login fields -->
<paper-input id="email" label="Email"></paper-input>
<paper-input id="password" label="Password" type="password"></paper-input>
<paper-button id="login" on-tap="signIn" disabled="[[disabled]]">
<iron-icon icon="account-circle"></iron-icon>
<span>Sign in</span>
</paper-button>
</template>
<script>
Polymer({
is: 'as-login',
properties: {
disabled: {
type: Boolean,
reflectToAttribute: true,
value: false
},
signedIn: {
type: Boolean,
reflectToAttribute: true,
value: false
}
},
signIn: function() {
this.fire('sign-in', null, { bubbles: false });
},
clearEmail: function() {
this.$.email.value = "";
},
clearPassword: function() {
this.$.password.value = "";
},
getEmail: function() {
return(this.$.email.value);
},
getPassword: function() {
return(this.$.password.value);
},
});
</script>
</dom-module>
And here is the app element
<as-login
id="login"
on-sign-in="signIn"
signed-in="[[signedIn]]"
disabled="[[!online]]">
</as-login>
<script>
Polymer({
is: 'as-app',
behaviors: [Polymer.AsAppBehaviour],
signIn: function() {
console.log("Let one sign in");
// Process sign in promise
this.$.auth.signInWithEmailAndPassword(this.$.login.getEmail(), this.$.login.getPassword())
.then(function(res) {
console.log("We signed in");
})
.catch(function(err) {
console.log("We got an error");
});
},
signOut: function() {
console.log("Let one sign out");
this.$.auth.signOut();
}
});
</script>

Data binding is recommended - see the attributes, value
<paper-input id="email" label="Email" value="{{email}}"></paper-input>
<paper-input id="password" label="Password" type="password" value="{{password}}"></paper-input>
The values can be accessed in your JS like this (instead of accessing the value through dom, this.$.login.email.value)
getEmail: function() {
return this.email;
},
getPassword: function() {
return this.password;
},

Related

Vue.js: Dynamically render html in child component's slot

In my vue.js application, I am trying to render the html content dynamically in child component's slot. If I enter the text only then there is no issue, it works with fine.
Here is my code:
ChildComponent.vue
<template>
<div :class="type" class="message" v-if="type">
<slot />
</div>
</template>
<script>
export default {
...
props: ['type'],
...
}
</script>
ParentComponent.vue
<script>
import Alert from '#/Alert';
export default {
components: {
Alert,
},
data() {
return {
...
alert: {
error: '',
message: '',
}
};
},
created () {
this._onLoad()
},
methods: {
_onLoad() {
axios.get(`api.call.here`).then((res) => {
...
}).catch(error => {
this.alert.error = error.type;
this.alert.message = `<p>message here</p>`; // from response
});
},
}
}
</script>
Here is the screenshot of the issue:
What you trying to do can be achieved with v-html. You can use it while calling your ChildComponent.vue. This is a small example for your case:
<Alert>
<span v-html="alert.message"></span>
</Alert>

Vue v-model on input as a dynamic ref

I created this <input> Vue component that handles a v-model property.
Adding the two-way data binding wasn't a problem, but I now want to add the current input value to the "state" so that I can clear it by just modifying a ref.
clearValue is called as expected but updating inputValue doesn't update the UI. What should I be doing differently ?
<template>
<div>
<input
:id="id"
type="text"
:value="inputValue"
#input="updateValue"
/>
<UiIcon
type="x"
#click.native="clearValue"
/>
</div>
</template>
<script lang="ts">
import { computed, defineComponent, ref } from '#nuxtjs/composition-api';
import UiIcon from '~/components/ui/UiIcon.vue';
export default defineComponent({
name: 'UiInput',
components: { UiIcon },
props: {
id: {
type: String,
required: true,
},
value: {
type: String,
default: undefined,
},
},
setup(props, { emit }) {
const inputValue = ref(props.value);
const clearValue = () => {
inputValue.value = '';
};
const updateValue = (event: Event) => {
emit('input', (event.target as HTMLInputElement).value);
};
return {
updateValue,
clearValue,
inputValue,
};
},
});
Usage example
data() {
return { text: '' };
},
template: `
<div>
<UiInput :id="id" v-model="text" />
</div>
`,
I think you just need to emit 'input' event with empty value inside clearValue function
emit('input', '');

Reset google autocomplete input value after select a location with VueJs

I need to clean up the google autocomplete input after select a location. I assigned a data value to the value prop of the component but seems like it doesn't change. Even using a watch, seem's like nothing happens.
This is my InputPlace component:
<template>
<label class="form-label-place" for="city">
<input class="form-control pr-5" :value="value" type="text" id="inputPlace" name="city" placeholder="Ingresa tu ciudad">
</label>
</template>
<script>
export default {
name: 'input-place',
props: {
value: ''
},
mounted() {
// Google autocomplete
const options = {
types: ['(cities)'],
componentRestrictions: {country: "PE"}
};
const places = new google.maps.places.Autocomplete(document.getElementById('inputPlace'), options);
google.maps.event.addListener(places, 'place_changed', () => {
this.$parent.placeChanged(places)
});
}
}
</script>
And this is how i'm using it into the view:
<template>
...
<input-place :value="InputPlaceValue"></input-place>
</template>
<script>
...
data() {
return {
activePlaces: [],
InputPlaceValue: ''
}
},
methods: {
placeChanged(places) {
let placeName = places.getPlace().name;
if(!this.activePlaces.includes(placeName)) this.activePlaces.push(placeName)
this.InputPlaceValue = ''
}
}
</script>
Hope you can help me, Thank you.
One option to clear autocomplete text field would be to:
a) use v-model directive
<input v-model="selectedAddress" class="form-control pr-5" type="text" id="inputPlace" name="city" placeholder="Ingresa tu ciudad">
b) and clear input value once place_changed event is triggered like this:
google.maps.event.addListener(places, "place_changed", () => {
this.selectedAddress = "";
});
InputPlace.vue example
<template>
<label class="form-label-place" for="city">
<input class="form-control" type="text" id="inputPlace" v-model="selectedAddress" name="city" placeholder="Search..">
</label>
</template>
<script>
export default {
/* global google */
name: "input-place",
data () {
return {
selectedAddress: ''
}
},
mounted() {
const options = {
types: ["(cities)"]
};
const places = new google.maps.places.Autocomplete(
document.getElementById("inputPlace"),
options
);
google.maps.event.addListener(places, "place_changed", () => {
this.selectedAddress = "";
this.$parent.placeChanged(places)
});
}
};
</script>

Vuejs component does not render immediately

I have a vue app and a component. The app simply takes input and changes a name displayed below, and when someone changes the name, the previous name is saved in an array. I have a custom component to display the different list items. However, the component list items do not render immediately. Instead, the component otems render as soon as I type a letter into the input. What gives? Why would this not render the list items immediately?
(function(){
var app = new Vue({
el: '#app',
components: ['name-list-item'],
data: {
input: '',
person: undefined,
previousNames: ['Ian Smith', 'Adam Smith', 'Felicia Jones']
},
computed: {
politePerson: function(){
if(!this.person) {
return 'Input name here';
}
return "Hello! To The Venerable " + this.person +", Esq."
}
},
methods: {
saveInput: function(event){
event.preventDefault();
if(this.person && this.previousNames.indexOf(this.person) === -1) {
this.previousNames.push(this.person);
}
this.setPerson(this.input);
this.clearInput();
},
returnKey: function(key) {
return (key + 1) + ". ";
},
clearInput: function() {
this.input = '';
},
setPerson: function(person) {
this.person = person;
}
}
});
Vue.component('name-list-item', {
props: ['theKey', 'theValue'],
template: '<span>{{theKey}} {{theValue}}</span>'
});
})()
And here is my HTML.
<div id="app">
<div class="panel-one">
<span>Enter your name:</span>
<form v-on:submit="saveInput">
<input v-model="input"/>
<button #click="saveInput">Save</button>
</form>
<h1>{{politePerson}}</h1>
</div>
<div class="panel-two">
<h3>Previous Names</h3>
<div>
<div v-for="person, key in previousNames" #click='setPerson(person)'><name-list-item v-bind:the-key="key" v-bind:the-value="person" /></div>
</div>
</div>
</div>
You are not defining your component until after you have instantiated your Vue, so it doesn't apply the component until the first update.

How to access polymer when "this" becomes "that"

I am trying to integrate dropzone.js and cloudinary into Polymer 1.0. It does work, but I am hitting a stumbling block on how to send the dynamic URL generated by Cloudinary back to Polymer so I can write that URL into Firebase. I am inside a function listening to dropzone events with the intention of using iron-signals to signal a different web component. "this" is now scoped to dropzone.js and not Polymer.
..resulting in "Uncaught TypeError: this.fire is not a function".
The code is below, I am trying to start the iron-signal based on listening the dropzone.js "success" event which provides access to the new image URL.
<link rel="stylesheet" href="../../../bower_components/dropzone/dist/min/dropzone.min.css">
<dom-module id="my-dropzone">
<style>
:host {
display: block;
}
div#my-dropzone-area {
max-width=300px;
height=300px;
border: 4px dashed blue;
}
</style>
<template>
<paper-button on-tap="startTheMessage">Test Fire!</paper-button>
<iron-signals on-iron-signal-hello="passTheMessage">
<div class="dropzone" id="my-dropzone-area">
<div class="fallback">
<input name="file" type="file" multiple />
</div>
</div>
</template>
</dom-module>
<script>
(function() {
Polymer({
is: 'my-dropzone',
ready: function() {
// access a local DOM element by ID using this.$
Dropzone.options.myDropzoneArea = {
paramName: 'file', // The name that will be used to transfer the file
maxFilesize: 10, // MB
uploadMultiple: false,
acceptedFiles: '.jpg,.png,.jpeg,.gif',
parallelUploads: 6,
addRemoveLinks: true,
url: 'https://api.cloudinary.com/v1_1/remarkable-ky/image/upload',
init: function() {
this.on('addedfile', function(file) {
console.log('Added file.');
console.log(file);
});
this.on('sending', function(file, xhr, formData) {
console.log('Sending file.');
formData.append('api_key', 0000000000000);
formData.append('timestamp', Date.now() / 1000);
formData.append('upload_preset', 'where-ky');
});
this.on('success', function(file, response) {
var baseURL = 'http://res.cloudinary.com/remarkable-ky/image/upload/';
var url = baseURL.concat(response.public_id);
console.log('Cloudinary URL: ', url);
this.fire('iron-signal', {
name: 'hello',
data: null
});
});
}
};
},
startTheMessage: function() {
this.fire('iron-signal', {
name: 'hello',
data: null
});
},
passTheMessage: function() {
alert("got it");
},
properties: {},
});
})();
</script>
<script src="../../../bower_components/dropzone/dist/min/dropzone.min.js"></script>
you can pass this into the function with the .bind() function.
this.on('success', function(file, response) {
var baseURL = 'http://res.cloudinary.com/remarkable-ky/image/upload/';
var url = baseURL.concat(response.public_id);
console.log('Cloudinary URL: ', url);
this.fire('iron-signal', {
name: 'hello',
data: null
});
}.bind(this));