firebase-collection : input value only updates first keystroke - firebase

I have a master-detail scenario. I'm using paper-datatable by David Mulder for my user-list. Data is populated through firebase collection
When tapping a row, a paper-dialog pops up with the details of the selected user.
When trying to edit a field, updating at firebase stops after one keystroke.
What am I missing?
<dom-module id="user-list">
<template>
<style>
:host {
#apply(--layout-vertical);
}
#editDialog {
min-width: 500px;
}
</style>
<firebase-collection location="https://<FIREBASE_APP>.firebaseio.com/users" data="{{users}}"></firebase-collection>
<paper-dialog id="editDialog" entry-animation="scale-up-animation" exit-animation="fade-out-animation" with-backdrop>
<div>
<paper-input value="{{selectedUser.name}}" label="Name" class="flex"></paper-input>
<paper-input value="{{selectedUser.username}}" label="Username" class="flex"></paper-input>
</div>
<div class="buttons">
<paper-button dialog-confirm autofocus>Ok</paper-button>
</div>
</paper-dialog>
<paper-datatable id="datatable" selected-item="{{selectedUser}}" selectable on-row-tap="_onDetail" data="{{users}}">
<div no-results>
Loading or no more items...
</div>
<paper-datatable-column header="Name" property="name" type="String" sortable style="min-width: 160px"></paper-datatable-column>
<paper-datatable-column header="Username" property="username" type="String" sortable style="min-width: 40px"></paper-datatable-column>
</paper-datatable>
</template>
<script>
Polymer({
is: 'user-list',
behaviors: [
Polymer.NeonAnimatableBehavior
],
properties: {
type: String,
selectedUser: {
type: Object,
notify: true
},
users: {
type: Array,
notify: true
},
animationConfig: {
value: function() {
return {
'entry': {
name: 'fade-in-animation',
node: this
},
'exit': {
name: 'fade-out-animation',
node: this
}
}
}
}
},
_onDetail: function() {
var dialog = document.getElementById('editDialog');
if (dialog) {
dialog.open();
}
}
})
</script>
</dom-module>

It seems firebase-collection isn't currently meant to be used in this way, it's more of a view into a Firebase location with data that's in an array-like structure. Although with the exception that you can add/delete new items but not update existing ones. See https://elements.polymer-project.org/elements/firebase-element?active=firebase-collection.
That said, each item in the collection has a __firebaseKey__ property that you could use to directly update that item in firebase.

Related

Polymer 2.0 + firebase can't update properly

I've got a problem using Polymer 2.0 and Firebase.
I want to update data to Firebase with firebase-document but when I want to update only the title, it destroy all the previous data and save only the title.
Example of the strucute before update :
myapp:
categories:
1:
logoName: test.png
title: test
And after :
myapp:
categories:
1:
title: test bis
Do I have to give always the entire record and update only the field I want or can I only give the field I want to update to saveValue.
I try to only give the field but it doesn't seem to work
Here is a part of my code :
<dom-module id="categorie-form">
<template>
<firebase-document
id="document"
app-name="myapp"
data="{{categorieData}}">
</firebase-document>
<iron-form id="categorieIronForm">
<form id="categorieForm">
<label for="title">Nom de la catégorie</label>
<input type="text" name="title" id="title" value="[[name]]">
<paper-button id="validButton" on-click="_submitCategorie" raised>valider</paper-button>
</form>
</iron-form>
</template>
<script>
class CategorieForm extends Polymer.Element {
static get is () { return "categorie-form" }
static get properties () {
return {
categorieData: {
type: Object
}
}
}
_submitCategorie () {
this.categorieData = {
title: form.title.value
};
this.$.document.saveValue('/categories', key)
}
}
customElements.define(CategorieForm.is, CategorieForm);
</script>
</dom-module>
Thank you
try this :
this.$.document.saveValue('/categories/1/title', key)

Pushing data to object in different component using POST

TL;DR I want to show submitted posts instantly instead of having to refresh my page
Using the Wordpress REST API I am able to create a new post without any issue. The post is being displayed as soon as the page refreshes, so what I want to do is update the posts object in my Hello.vue file as soon as I create that post so I don't need to refresh to show my newest posts.
I'm not really sure where to start - I've removed all of the experiments I've done so far (importing Post in Create, defining props, pushing to an array, reading about object reactivity on the official Vue documentation, nothing helped).
My App.js consists of the <router> object which shows Hello.vue and a component called Create which displays the Create.vue component. This is how my app currently looks like:
My App.vue file:
<template>
<div id="app">
<section class="posts">
<router-view></router-view>
<create></create>
</section>
</div>
</template>
<script>
import Create from '#/components/Create.vue'
export default {
name: 'app',
components: {
Create
}
}
</script>
<style lang="scss">
#import '../src/assets/styles/style.scss'
</style>
My Hello.vue which displays all the posts:
<template>
<div>
<section class="posts__Feed">
<ul class="posts__List">
<post v-for="item in posts" :item="item" :key="item.id"></post>
</ul>
</section>
</div>
</template>
<script>
var postsUrl = '/wp-json/wp/v2/posts/'
import Post from '#/components/Post.vue'
export default {
name: 'hello',
props: ['responseData'],
components: {
Post
},
data () {
return {
posts: []
}
},
beforeCreate () {
this.$http.get(postsUrl).then((response) => {
this.posts = response.data
})
}
}
</script>
And finally, the Create.vue file which creates the post:
<template>
<div>
<section class="posts__Create">
<form class="posts__CreateForm" v-on:submit="createPosts">
<div class="posts__CreateFormWrapper" v-bind:class="{ 'is-Loading': loading }">
<p>
<input v-model="formInfo.title" type="text" name="title" id="title" placeholder="Name" :disabled="formSent">
</p>
<p>
<textarea v-model="formInfo.content" name="content" id="content" cols="20" rows="10" maxlength="140" placeholder="Message" :disabled="formSent"></textarea>
</p>
<p>
<button :disabled="formSent">Send</button>
</p>
</div>
</form>
</section>
</div>
</template>
<script>
var postsUrl = '/wp-json/wp/v2/posts/'
export default {
name: 'create',
data () {
return {
formInfo: [],
responseData: [],
loading: false,
formSent: false
}
},
methods: {
createPosts (e) {
e.preventDefault()
var info = this.formInfo
// Check if fields are empty
if (this.formInfo.title && this.formInfo.content) {
this.loading = true
// POST
this.$http.post(postsUrl, info).then((response) => {
this.formSent = true
this.loading = false
// get body data
this.responseData = response.data
})
}
} // EOF createPosts
}
}
</script>
Any help would be much appreciated!
I ended up using an event bus as suggested by wotex. First, I've createad a file called bus.js with the below code:
import Vue from 'vue'
export const EventBus = new Vue()
Next, import bus.js to both .vue layouts using:
import { EventBus } from '#/bus.js'
Now emit the event as soon as a new post is created (this is sitting in my axios POST request inside the Create.vue file):
EventBus.$emit('newPost', this.responseData)
And finally, check if the event has happened on the other end (my Hello.vue file):
EventBus.$on('newPost', function (postData) {
Thanks for pointing me in the right direction!

How to pass parameter data between templates in meteor flowlayout flowrouter

I have a template called : Orders which shows my orders collection of images :
{{#each images}}
<div class="images">
<img class="image" src="{{this.url }}" />
</div>
{{/each}}
No I want another tempate called order to show me only one item from collection that I click on: I try doing this way: 1. orders.js events for click on image:
"click .image": function() {
Images.find({_id:this._id});
and orders.html:
<img class="image" src="{{this.url }}" />
I also have routes.js :
FlowRouter.route("/orders", { **this part works fine**
action: function(){
FlowLayout.render("layout",{top:"orders", main:"test"});
}
FlowRouter.route('/order/', { **How do I do this part ????????**
action: function(){
FlowLayout.render("layout",{top:"order",data:image});
}
I used a dynamic layout template to show orders which shows fine.
How do I set the single order html , route and render ????
To answer your question:
Beginning by your route, you should pass the id parameter in the path like that :
FlowRouter.route('/order/:imageId', {
action: function() {
FlowLayout.render("layout",{ top: "order", main: "test" });
}
});
Looking at the rendering on order.html file which contains the template order, something like:
<template name="order">
{{#with image}}
<!-- whatever you want to do -->
<img src="{{url}}" />
{{/with}}
</template>
This template uses order.js with a subscription to your collection for one image only and a helper called image which look for the parameter imageId you transmitted in your route via the function FlowRouter.getParam:
Template.order.onCreated(function() {
var imageId = FlowRouter.getParam('imagedId');
if ( imageId !== undefined ) {
Meteor.subscribe('oneImage', imageId);
}
}
Template.order.helpers({
image: function() {
var imageId = FlowRouter.getParam('imagedId');
if ( imageId !== undefined ) {
return Images.findOne({ _id: imageId });
}
}
}
And to conclude, server side, you shall do a publication:
Meteor.publish('oneImage', function(imageId) {
return Images.findOne({ _id: imageId });
}
Following this way, you don't need anymore your event click .image and you optimized your performance! ;)
Btw on orders.html in your {{#each}} loop, you don't need to write {{this.url}} nor {{this._id}}, {{url}} and {{_id}} are fine ;)
To retrieve request parameter you can use:
FlowRouter.current().route._params.keys.id

Attribute bind-value is not set in iron-input when initiated

Here's a pattern I try to do with Polymer:
<link rel="import" href="/bower_components/polymer/polymer.html" />
<link rel="import" href="/bower_components/iron-ajax/iron-ajax.html" />
<link rel="import" href="/bower_components/iron-input/iron-input.html" />
<dom-module id="my-entity">
<template>
<iron-ajax auto url="{{urlGet}}" handle-as="json" last-response="{{entity}}"></iron-ajax>
<iron-ajax id="updateEntityCall" url="{{urlUpdate}}" handle-as="json" on-response="handleUpdateResponse"></iron-ajax>
<div>
<div class="input-wrapper">
<label>Name : </label>
<input is="iron-input" bind-value="{{entityName}}" value="{{entity.name}}" />
</div>
<div>
<button on-click="saveEntity">Save</button>
</div>
</div>
</template>
<script>
Polymer(
{
is: "my-entity",
properties: {
entityid: {
notify: true
},
entityName: {
notify: true
}
urlGet: {
computed: 'getUrlGet(entityid)'
},
urlTemplate: {
computed: 'getUrlUpdate(entityid, entityName)'
},
},
getUrlGet: function (entityId) {
return ['/path/to/get', entityId].join('/');
},
getUrlUpdate: function (entityId, entityName) {
return ['/path/to/update', entityId, entityName].join('/');
},
saveEntity: function (e, detail, sender) {
this.$.updateEntityCall.generateRequest();
}
}
);
</script>
</dom-module>
I first create a iron-ajax that will get some data from an entity. This will be printed in a iron-input element so a person will be able to update this entity.
The iron-ajax is bound to a {{entity}} variable that is used by the value in the iron-input element (entity.name). I have created a property called entityName that will be bound at the bind-value attribute of this same iron-input.
Once someone has made the change, the goal is that he/she clicks on the button that calls the function saveEntity, that basically call the other iron-ajax element.
There is no problem with this code when someone actually change the value of the iron-input. The problem appear when the user don't change the value and click the button. It sends nothing, like if entityName is not set.
This is a simple example, in my use-case I have 3 fields and 2 of them can have "empty strings" as valid value.

Reactive-Tables Meteor

I am trying to get reactive-tables to work but I am having no luck following the instructions on GitHub.
This is what I have:
In my Main.html:
{{> courseTable }}
in my course_table.html:
<template name="courseTable">
<div id="table">
{{ > reactiveTable collection=Courses}}
</div>
</template>
in courses.js:(works with autoForm)
Courses = new Meteor.Collection("courses", {
schema: {....
Is there something I am missing? From my understanding once these commands are used, the rest is done from within the package. I can't find any more information on this package anywhere.
What I have now just shows a blank screen.
Thanks in advance!
This is what I have: (I'm using Meteor framework and bootstrap-3 package)
in index.html
<template name="clientes">
<div class="container">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">Clientes</h3>
</div>
<div class="panel-body">
{{> reactiveTable collection=tables settings=tableSettings}}
</div>
</div>
</div>
</template>
in index.js
var Clientes = new Meteor.Collection('clientes')
Template.clientes.tables = function () {
return Clientes;
}
Template.clientes.tableSettings = function () {
return {
rowsPerPage: 10,
showFilter: false,
showNavigation: 'auto',
fields: [
{ key: 'nombre', label: 'Nombre' },
{ key: 'apellido', label: 'Apellido' },
{ key: 'correoe', label: 'E-mail' }
],
useFontAwesome: true,
group: 'client'
};
}
With this I can display all the records in the collection.
I hope this help you to go any further.
Courses is the collection object. To get some courses, you need to query the courses with find:
Courses.find()
However, to make this accessible in the template, you need a helper function.
//course_table.js
Template.courseTable.helpers({
courses: function () {
return Courses.find()
}
});
Then you can can set the table collection using the helper method (I used a lowercase "courses" for the helper method for clarity):
{{> reactiveTable collection=courses}}

Resources