I have a strange problem. When I try to update a specific document in an array of documents on Firebase, it always update the last document, even if I specified the document with the auto-generated ID. Also, it isn't updated instantly although I'm using snapshot
this is the project repo: [redacted]
<template>
<div class="dashboard">
<h1 class="subheading grey--text">Dashboard</h1>
<v-container class="">
<v-layout row>
<v-tooltip top>
<template v-slot:activator="{ on, attrs }">
<v-btn small text class="mb-5 ml-5" v-bind="attrs" v-on="on" #click="sortBy('title')">
<v-icon left>mdi-sort</v-icon>
<span>sort by project name</span>
</v-btn>
</template>
<span>sort by project name</span>
</v-tooltip>
<v-tooltip top>
<template v-slot:activator="{ on, attrs }">
<v-btn small text class="mb-5 ml-5" v-bind="attrs" v-on="on" #click="sortBy('person')">
<v-icon left>mdi-sort</v-icon>
<span>sort by person</span>
</v-btn>
</template>
<span>sort by person</span>
</v-tooltip>
</v-layout>
<v-card flat :class="`grey lighten-3 mb-1 border project ${project.status}`" v-for="(project, i) in projectsArray" :key="i" :id="project.id">
<div class="edit-list">
<!-- Delete Button -->
<button #click="deleteProject(project.id)" class="deleteProject small mx-1 grey v-btn v-btn--outlined v-btn--text theme--dark v-size--default">
<v-icon left>mdi-delete</v-icon>
delete
</button>
<!-- Edit Button -->
<v-dialog v-model="dialog" persistent max-width="600" >
<template v-slot:activator="{ on, attrs }">
<v-btn v-bind="attrs" v-on="on" dark
class="modifyProject small mx-1 grey v-btn v-btn--outlined v-btn--text theme--dark v-size--default" >
<v-icon left>mdi-pencil</v-icon>
edit
</v-btn>
</template>
<v-card>
<v-card-title class="text-h5">
edit project #: {{project.id}}
</v-card-title>
<v-card-text>
<v-text-field v-model="newTitle" placeholder="project title">{{project.title}}</v-text-field>
<v-text-field v-model="newContent" placeholder="project content">{{project.content}}</v-text-field>
<v-text-field v-model="newDue" placeholder="project due date">{{project.due}}</v-text-field>
new title: {{newTitle}}
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="grey lighten-3" class="green--text" #click="modifyProject(project.id)" > Apply </v-btn>
<v-btn color="grey lighten-3" class="red--text" #click="dialog = false" > Cancel </v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</div>
<v-layout class="no-gutters pa-1" wrap row>
<v-flex xs12 sm4 md3 class="px-2 primary--text">
<div class="caption primary--text pa-1 font-weight-bold">Project Title</div>
<div class="black--text">{{ project.title }}</div>
<div class="red--text caption">ID: {{ project.id }}</div>
</v-flex>
<v-flex xs12 sm8 md3 class="px-2 primary--text">
<div class="caption primary--text pa-1 font-weight-bold">Project content</div>
<div class="black--text">{{ project.content }}</div>
</v-flex>
<v-flex xs12 sm4 md2 class="px-2 primary--text">
<div class="caption primary--text pa-1 font-weight-bold">Person</div>
<div class="black--text">{{ project.person }}</div>
</v-flex>
<v-flex xs12 sm4 md2 class="px-2 primary--text">
<div class="caption primary--text pa-1 font-weight-bold">Due date</div>
<div class="black--text">{{ project.due }}</div>
</v-flex>
<v-flex xs12 sm4 md2 class="px-md-2 primary--text">
<div class="caption primary--text pa-1 font-weight-bold">Project status
<v-chip small :class="`${project.status} dark--text caption mt-4 px-3 mr-5`">
{{project.status}}
</v-chip>
</div>
</v-flex>
</v-layout>
</v-card>
</v-container>
</div>
</template>
<script>
import db from '../firebase'
import { collection, query, onSnapshot, deleteDoc, doc, updateDoc } from "firebase/firestore";
export default {
data: ()=>{
return{
absolute: false,
overlay: false,
projectsArray: [],
dialog: false,
title: '',
content: '',
due: '',
date: (new Date(Date.now() - (new Date()).getTimezoneOffset() * 60000)).toISOString().substr(0, 10),
menu: false,
loading: false,
updatedTitle: '',
updatedContent: '',
updatedDue: '',
newTitle: '',
newDue: '',
newContent: ''
}
},
methods:{
sortBy(prop){
this.projectsArray.sort((a,b) =>
a[prop] < b[prop] ? -1: 1)
},
async deleteProject(id){
await deleteDoc(doc(db, "Projects", id))
console.log(id + ' ---- was deleted -----');
},
async modifyProject(id){
const selectedProject = doc(db, "Projects", id);
await updateDoc(selectedProject, {
title : this.newTitle,
content : this.newContent,
due : this.newDue
// title: 'new title',
// content: 'new content',
// due: '12-12-2012'
});
this.dialog = false
console.log('project with ID: ' + id + ' was modified successfully!!');
},
cancel(){
this.title = '',
this.content = '',
this.due = null,
this.dialog = false
}
},
async created(){
const q = query(collection(db, "Projects"));
onSnapshot(q, snapshot => {
snapshot.docChanges().forEach(change => {
let target = document.getElementById(change.doc.id);
if (change.type === "added") {
this.projectsArray.push({
...change.doc.data(),
id: change.doc.id
})
console.log("New project with id:", change.doc.data());
}
if (change.type === "modified") {
change.doc.data().title = this.newTitle
change.doc.data().content = this.newContent
change.doc.data().due = this.newDue
console.log(change.doc.data().title);
const updated = query(collection(db, "Projects"))
console.log("modified project: ", updated);
}
if (change.type === "removed") {
target.parentElement.removeChild(target);
}
});
});
}
}
</script>
<style scoped>
.border{
border: 1px solid #000 !important;
}
.project{position: relative;}
.project.completed{
border-left: 5px solid #12be6e !important;
}
.project.ongoing{
border-left: 5px solid #ebee22 !important;
}
.project.overdue{
border-left: 5px solid #e32 !important;
}
.w-fit{
width: fit-content !important;
}
.v-chip.completed{
background-color: #12be6e !important;
color: #fff;
}
.v-chip.ongoing{
background-color: #ebee22 !important;
}
.v-chip.overdue{
background-color: #e32 !important;
color: #fff;
}
.v-icon.mdi-pencil, .v-icon.mdi-delete{
transition: 0.1s;
color: white;
}
.v-icon.mdi-pencil:hover{
color: #12be6e;
}
.v-icon.mdi-delete:hover{
color: #e32;
}
.deleteProject{
transition: 0.1s;
}
.deleteProject:hover, .deleteProject:hover .v-icon.mdi-delete{
color: #e32;
background-color: transparent !important;
}
.modifyProject{
transition: 0.1s;
}
.modifyProject:hover, .modifyProject:hover .v-icon.mdi-pencil{
color: #12be6e;
background-color: transparent !important;
}
.v-card--reveal {
align-items: center;
bottom: 0;
justify-content: center;
opacity: 0.85;
position: absolute;
width: 100%;
}
.project .edit-list{
display: flex;
align-items: center;
justify-content: center;
color: #fff;
opacity: 0;
content: '';
z-index: 2;
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-color: rgba(0,0,0,0.5);
transition: 0.25s;
}
.project:hover .edit-list{
opacity: 1;
}
</style>
And this is the firebase structure
It seems like you are getting the wrong document when using the method doc() method. You can try to use getdoc() in your code part mentioned below.
async modifyProject(id){
const selectedProject = doc(db, "Projects", id);
await updateDoc(selectedProject, {
title : this.newTitle,
content : this.newContent,
due : this.newDue
Also, can you please change the method a bit to add a line in your logs to see what you are getting from the method before sending it to update.
Related
I am currently trying to implemented a draggable re-orderable list with Framer Motion. I am trying to reproduce the following behaviour:
https://codesandbox.io/s/framer-motion-5-drag-to-reorder-lists-uonye?from-embed=&file=/src/Icon.tsx:49-54
I have an ingredientList that contains the create_index of the each of the ingredients created in my Formik form, which are accessible as values.ingredients.
The main issue I am having is that the list items are not behaving smoothly as they do in the code example and I'm not sure what I am doing wrong
This is my parent component in which I set the ingredientList
const IngredientTab = ({values}: any) => {
const [ingredientList, setIngredientList] = useState(values.ingredients.map((ingredient) => ingredient.create_index))
return (
<div css={IngredientTabStyles}>
<FieldArray name="ingredients">
{({ insert, remove, push }) => (
<div>
<Reorder.Group axis="y" values={ingredientList} onReorder={setIngredientList}>
<AnimatePresence>
{ingredientList.map((ingredientUniqueValue, index) => {
return (
<Ingredient
key={index}
index={index}
uniqueValue={ingredientUniqueValue}
ingredients={values.ingredients}
order={`${ingredientList.indexOf(ingredientUniqueValue) + 1}`}
/>
)
})}
</AnimatePresence>
</Reorder.Group>
<button
type="button"
className="add-ingredients"
onClick={() => {
setIngredientList([...ingredientList, values.ingredients.length])
push({ name: '', additional_info: '', quantity: '', unit_id: '', create_index: values.ingredients.length})
}}
>
Add Ingredient
</button>
</div>
)}
</FieldArray>
</div>
)
}
export default IngredientTab
const IngredientTabStyles = css`
.ingredient-fields {
margin-bottom: 2rem;
background-color: white;
}
`
And this is the Item component:
const Ingredient = ({ uniqueValue, ingredients, order, ingredient}: any) => {
const y = useMotionValue(0);
const boxShadow = useRaisedShadow(y);
const ingredientIndex = ingredients.findIndex(ingredient => ingredient.create_index==uniqueValue)
return (
<Reorder.Item
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
key={uniqueValue}
value={uniqueValue}
style={{boxShadow,y}}
>
{ingredient}
<div className="ingredient-fields" css={IngredientStyles}>
<div className="order">
<h6>{order}</h6>
</div>
<div className="ingredient-name">
<Field
name={`ingredients.${ingredientIndex}.name`}
type='text'
placeholder="Ingredient"
/>
<Field
name={`ingredients.${ingredientIndex}.additional_info`}
type='text'
placeholder="Description"
/>
</div>
<Field
name={`ingredients.${ingredientIndex}.quantity`}
type='number'
placeholder="Quantity"
/>
</div>
</Reorder.Item>
)
}
export default Ingredient
const IngredientStyles = css`
display: flex;
margin-bottom: 2rem;
.order {
display: flex;
align-items: center;
background-color: ${theme.components.grey};
padding: 1rem 2rem;
margin-right: 2rem;
border-radius: 0.4rem;
}
.ingredient-name {
display: flex;
}
input {
padding-bottom: 1rem;
border: none;
border-bottom: 1px solid ${theme.colors.lightGrey};
font-family: 'Source Sans Pro', sans-serif;
font-weight: 300;
}
`
I tried to take screenshots of the behaviour that I currently have. If I try to drag the 'bonjour' to the first position, the 1st item 'hello' does not move downwards. Instead what happens onReorder, what you see in the second picture, the bonjour and hello abruptly switch and it looks as though I am dragging the 'hello' item
Script :
<v-date-picker v-model="date" #input="changeHours" no-title>
<div class="flex-grow-1"></div>
<v-btn text color="primary" #click="modal = false">Cancel</v-btn>
<v-btn text color="primary" #click="$refs.dialog.save(date)">OK</v-btn>
</v-date-picker>
Demo and full codepen : https://codepen.io/positivethinking639/pen/RwwQpxm
I want to set height of scroll. So the scroll not past the footer or the time schedule displayed is 5 data
How can I do it?
Yes it is possible to set the height of scroll times nest to datepicker.
By default dialog box comes with the scroll that has to be disabled
first, the we can add scroll separately to date picker or time flex
box
Here in the below code, I've moved the datepicker footer buttons as a separate flex and added scroll only to the times, So that it can grow based on number fo time slots
Working codepen here: https://codepen.io/chansv/pen/vYYdKNJ
<div id="app">
<v-app>
<v-content>
<v-container>
<v-btn color="success" dark #click="openModal()">call date {{ date }}</v-btn>
<v-dialog
:return-value.sync="date"
v-model="modal"
content-class="dialog-class"
ref="dialog"
persistent
>
<v-card>
<div>
<v-container grid-list-md text-xs-cente style="padding: 0px;">
<v-layout row wrap>
<v-flex xs8 style="position: fixed;">
<v-date-picker v-model="date" #input="changeHours" no-title>
</v-date-picker>
</v-flex>
<v-flex xs4 style="position: relative; left: 300px;">
<div>
<p class="text-center mt-3 font-weight-bold">Select Time</p> </div>
<p class="text-center subtitle-2 mt-4" v-if="!allowedTimes.length">Please pick date first</p>
<p class="text-center" v-if="!allowedTimes.length"><v-icon>event</v-icon></p>
<div class="my-3" v-show="date !== null" :style="{'background-color':'white','text-align':'center', 'overflow-y': 'scroll', 'height': '220px'}">
<template v-for="(allowedTime, i) in allowedTimes">
<v-btn
:key="i"
#click="setTime(allowedTime)"
class="my-1"
:outlined="allowedTime !== time"
color="primary"
>{{ allowedTime }}</v-btn>
</template>
</div>
</v-flex>
<v-flex xs12>
<v-card>
<v-card-actions style="padding-top: 0px;">
<v-spacer></v-spacer>
<v-btn color="primary" #click="modal = false">Cancel</v-btn>
<v-btn color="primary" #click="$refs.dialog.save(date)">OK</v-btn>
</v-card-actions>
</v-card>
</v-flex>
</v-layout>
</v-container>
</div>
</v-card>
</v-dialog>
</v-container>
</v-content>
</v-app>
</div>
css
.v-dialog { box-shadow: none!important; }
.row {
margin-right: 0 !important;
}
.v-picker__body {
flex: none !important;
}
.v-card{
box-shadow: none !important;
}
.dialog-class {
overflow: hidden;
max-height: 345px !important;
max-width: 470px;
}
.v-date-picker-table {
position: relative;
padding: 0 12px;
height: 220px;
}
script
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
date: new Date().toISOString().substr(0, 10),
modal: false,
footer: false,
time: null,
allowedTimes: ['13:00 - 14:00','14:00 - 15:00','15:00 - 16:00','16:00 - 17:00','17:00 - 18:00','18:00 - 19:00','19:00 - 20:00','20:00 - 21:00','21:00 - 22:00']
// allowedTimes: []
}),
methods: {
save(k) {
console.log(this.$refs.dialog);
},
allowedDates: val => parseInt(val.split('-')[2], 10) % 2 === 0,
setTime(time) {
this.time = time
},
changeHours(_val) {
console.log(_val)
this.allowedTimes = ['08:00 - 09:00','09:00 - 10:00']
},
openModal() {
this.modal = true
var self = this;
setTimeout(() =>{
self.setFooter()
}, 0);
},
setFooter() {
if (!this.footer) {
console.log('footer')
var div = document.createElement('div');
var html = "<span><div style='float:left; margin-top:4px; margin-left: 10px; height: 12px; width: 12px; border-radius: 10px; background-color: blue;'></div></span><span style='margin-left: 5px; float: left;font-size:14px'>Available</span><span><div style='float:left;height: 12px; width: 12px; border-radius: 10px; background-color: grey; margin-left:20px; margin-top:4px;'></div></span><span style='margin-left: 8px; float:left; font-size: 14px'>Unavailable</span>";
div.innerHTML = html;
document.querySelector('.v-date-picker-table').append(div);
this.footer = true;
}
}
},
})
I'm currently trying to develop a web form that uses HTML so that users can visit this webpage and drag and drop thousands of photos. After providing an email address, these photos would be directly sent to one of our Google Drive accounts inside a subfolder of the user's email address and the time of submission.
I've played around with this code, but nowhere did I find a place for me to connect my Google Drive account.
<body>
<div id="formcontainer">
<label for="myForm">Facilities Project Database Attachment Uploader:</label>
<br><br>
<form id="myForm">
<label for="myForm">Project Details:</label>
<div>
<input type="text" name="zone" placeholder="Zone:">
</div>
<div>
<input type="text" name="building" placeholder="Building(s):">
</div>
<div>
<input type="text" name="propertyAddress" placeholder="Property Address:">
</div>
<div>
<label for="fileText">Project Description:</label>
<TEXTAREA name="projectDescription"
placeholder="Describe your attachment(s) here:"
style ="width:400px; height:200px;"
></TEXTAREA>
</div>
<br>
<label for="attachType">Choose Attachment Type:</label>
<br>
<select name="attachType">
<option value="Pictures Only">Picture(s)</option>
<option value="Proposals Only">Proposal(s)</option>
<option value="Pictures & Proposals">All</option>
</select>
<br>
<label for="myFile">Upload Attachment(s):</label>
<br>
<input type="file" name="filename" id="myFile" multiple>
<input type="button" value="Submit" onclick="iteratorFileUpload()">
</form>
</div>
<div id="output"></div>
<div id="progressbar">
<div class="progress-label"></div>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script>
var numUploads = {};
numUploads.done = 0;
numUploads.total = 0;
// Upload the files into a folder in drive
// This is set to send them all to one folder (specificed in the .gs file)
function iteratorFileUpload() {
var allFiles = document.getElementById('myFile').files;
if (allFiles.length == 0) {
alert('No file selected!');
} else {
//Show Progress Bar
numUploads.total = allFiles.length;
$('#progressbar').progressbar({
value : false
});//.append("<div class='caption'>37%</div>");
$(".progress-label").html('Preparing files for upload');
// Send each file at a time
for (var i = 0; i < allFiles.length; i++) {
console.log(i);
sendFileToDrive(allFiles[i]);
}
}
}
function sendFileToDrive(file) {
var reader = new FileReader();
reader.onload = function (e) {
var content = reader.result;
console.log('Sending ' + file.name);
var currFolder = 'Something';
google.script.run.withSuccessHandler(updateProgressbar).uploadFileToDrive(content, file.name, currFolder);
}
reader.readAsDataURL(file);
}
function updateProgressbar( idUpdate ){
console.log('Received: ' + idUpdate);
numUploads.done++;
var porc = Math.ceil((numUploads.done / numUploads.total)*100);
$("#progressbar").progressbar({value: porc });
$(".progress-label").text(numUploads.done +'/'+ numUploads.total);
if( numUploads.done == numUploads.total ){
//uploadsFinished();
numUploads.done = 0;
};
}
</script>
<script>
function fileUploaded(status) {
document.getElementById('myForm').style.display = 'none';
document.getElementById('output').innerHTML = status;
}
</script>
<style>
body {
max-width: 400px;
padding: 20px;
margin: auto;
}
input {
display: inline-block;
width: 100%;
padding: 5px 0px 5px 5px;
margin-bottom: 10px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
select {
margin: 5px 0px 15px 0px;
}
input[type="submit"] {
width: auto !important;
display: block !important;
}
input[type="file"] {
padding: 5px 0px 15px 0px !important;
}
#progressbar{
width: 100%;
text-align: center;
overflow: hidden;
position: relative;
vertical-align: middle;
}
.progress-label {
float: left;
margin-top: 5px;
font-weight: bold;
text-shadow: 1px 1px 0 #fff;
width: 100%;
height: 100%;
position: absolute;
vertical-align: middle;
}
</style>
</body>
Source: Uploading Multiple Files to Google Drive with Google App Script
I have the following directive:
import Vue from 'vue'
const Dialog = Vue.extend({
template: `
<div v-if="show" class="modal">
<div class="modal-body">
<div class="modal-header"><h3>Aktion bestätigen</h3></div>
<div class="modal-content">
<div class="uk-flex">
<div class="uk-margin-small-right">
<span uk-icon="icon: question; ratio: 3"></span>
</div>
<div>
Are You sure?
</div>
</div>
<hr>
<div class="uk-flex uk-flex-right">
<button class="uk-button uk-button-danger uk-margin-small-right" #click="confirmed">Yes</button>
<button class="uk-button uk-button-default" #click="show = false">Cancel</button>
</div>
</div>
</div>
</div>
`
});
Vue.directive('confirm', {
bind(el, binding, vnode) {
let confirm_method = binding.value;
el.handleClick = (e) => {
const data = { confirmed: confirm_method , show: true};
let dialog = new Dialog({data: data}).$mount();
document.getElementsByTagName('body')[0].appendChild(dialog.$el);
}
el.addEventListener('click', el.handleClick);
},
unbind(el) {
el.removeEventListener('click', el.handleClick);
}
});
This works fine. When I click on "Cancel", the modal closes. When I click "Yes", the method defined in Vue template
<button v-confirm="delete">delete</button>
is executed.
But the modal does not appear. How to tell the modal to close after the method has been executed, and maybe show an error message, when there was an error?
You can pass methods to Dialog:
Vue.directive('confirm', {
bind(el, binding, vnode) {
let confirm_method = binding.value;
el.handleClick = (e) => {
const data = { confirmed: confirm_method , show: true};
let dialog = new Dialog({
data: data,
methods: {
confirmedInternal() {
this.show = false
this.confirmed()
}
}
}).$mount();
document.getElementsByTagName('body')[0].appendChild(dialog.$el);
}
el.addEventListener('click', el.handleClick);
},
unbind(el) {
el.removeEventListener('click', el.handleClick);
}
});
then calling confirmedInternal when yes button is click
<button class="uk-button uk-button-danger uk-margin-small-right" #click="confirmedInternal">Yes</button>
Demo: https://jsfiddle.net/guqc2src/
Vue documentation has pretty good example of modal.
The key option is $emit('close'). You can call $emit('close') on your method success.
// register modal component
Vue.component('modal', {
template: '#modal-template'
})
// start app
new Vue({
el: '#app',
data: {
showModal: false
}
})
.modal-mask {
position: fixed;
z-index: 9998;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, .5);
display: table;
transition: opacity .3s ease;
}
.modal-wrapper {
display: table-cell;
vertical-align: middle;
}
.modal-container {
width: 300px;
margin: 0px auto;
padding: 20px 30px;
background-color: #fff;
border-radius: 2px;
box-shadow: 0 2px 8px rgba(0, 0, 0, .33);
transition: all .3s ease;
font-family: Helvetica, Arial, sans-serif;
}
.modal-header h3 {
margin-top: 0;
color: #42b983;
}
.modal-body {
margin: 20px 0;
}
.modal-default-button {
float: right;
}
/*
* The following styles are auto-applied to elements with
* transition="modal" when their visibility is toggled
* by Vue.js.
*
* You can easily play with the modal transition by editing
* these styles.
*/
.modal-enter {
opacity: 0;
}
.modal-leave-active {
opacity: 0;
}
.modal-enter .modal-container,
.modal-leave-active .modal-container {
-webkit-transform: scale(1.1);
transform: scale(1.1);
}
<script src="https://unpkg.com/vue#2.5.16/dist/vue.js"></script>
<!-- template for the modal component -->
<script type="text/x-template" id="modal-template">
<transition name="modal">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<slot name="header">
default header
</slot>
</div>
<div class="modal-body">
<slot name="body">
default body
</slot>
</div>
<div class="modal-footer">
<slot name="footer">
default footer
<button class="modal-default-button" #click="$emit('close')">
OK
</button>
</slot>
</div>
</div>
</div>
</div>
</transition>
</script>
<!-- app -->
<div id="app">
<button id="show-modal" #click="showModal = true">Show Modal</button>
<!-- use the modal component, pass in the prop -->
<modal v-if="showModal" #close="showModal = false">
<!--
you can use custom content here to overwrite
default content
-->
<h3 slot="header">custom header</h3>
</modal>
</div>
Anyone know how to get the sliders in this codepen example to manipulate the chart data for it's category? Currently only the Citizenship category is affected.
var valueBubble = '<output class="rangeslider__value-bubble" />';
function updateValueBubble(pos, value, context) {
pos = pos || context.position;
value = value || context.value;
var $valueBubble = $('.rangeslider__value-bubble', context.$range);
var tempPosition = pos + context.grabPos;
var position = (tempPosition <= context.handleDimension) ? context.handleDimension : (tempPosition >= context.maxHandlePos) ? context.maxHandlePos : tempPosition;
if ($valueBubble.length) {
$valueBubble[0].style.left = Math.ceil(position) + 'px';
$valueBubble[0].innerHTML = value;
}
}
$('input[type="range"]').rangeslider({
polyfill: false,
onInit: function() {
this.$range.append($(valueBubble));
updateValueBubble(null, null, this);
},
onSlide: function(pos, value) {
updateValueBubble(pos, value, this);
updateChart(0, value);
}
});
function updateChart(location, value) {
myChart.data.datasets[0].data[location] = value;
myChart.update();
}
var ctx = document.getElementById("polarChart").getContext('2d');
var myChart = new Chart(ctx, {
type: 'polarArea',
data: {
labels: [
"Citizenship",
"People",
"Growth",
"Management",
"Relationships",
"Health",
"Wealth",
"Joy"
],
datasets: [{
backgroundColor: [
"#00A3CE",
"#22CBED",
"#EB67A2",
"#FDA9ED",
"#EC5B22",
"#F78F21",
"#148F1E",
"#1EC428"
],
data: [4, 6, 6, 2, 4, 2, 2, 7],
}],
},
options: {
elements: {
arc: {
borderColor: "rgba(255,255,255,1)",
borderWidth: 2
}
},
scale: {
ticks: {
beginAtZero: true,
max: 8,
min: 0,
stepSize: 1,
fontFamily: "'Lato', sans-serif",
fontSize: 18,
fontColor: "#000",
display: false
},
gridLines: {
lineWidth: 1,
color: "#999"
},
},
layout: {
padding: {
left: 100,
right: 200,
top: 10,
bottom: 10
}
},
legend: {
display: true,
position: "right",
labels: {
fontFamily: "'Lato', sans-serif",
fontSize: 18,
fontColor: "#000"
}
}
}
});
#import "compass/css3";
body {
padding: 50px 0;
}
.sliderHolder {
width: 20%;
//height:400px;
float: left;
//border:1px solid;
//display:none;
}
.wheelCat {
width: 100px;
float: left;
//border:1px solid;
padding-top: 55px;
text-align: right;
padding-right: 10px;
font-family: "Lato", san-serif;
font-size: 13px;
}
.sliderAll {
height: 100px;
width: 50%;
padding-top: 55px;
//border:1px solid;
float: left;
}
.sliderCitizenship .rangeslider__fill {
background-color: #00A3CE;
}
.sliderPeople .rangeslider__fill {
background-color: #22CBED;
}
.sliderGrowth .rangeslider__fill {
background-color: #EB67A2;
}
.sliderManagement .rangeslider__fill {
background-color: #FDA9ED;
}
.sliderRelationships .rangeslider__fill {
background-color: #EC5B22;
}
.sliderHealth .rangeslider__fill {
background-color: #F78F21;
}
.sliderWealth .rangeslider__fill {
background-color: #148F1E;
}
.sliderJoy .rangeslider__fill {
background-color: #1EC428;
}
.rangeslider__value-bubble {
display: none;
}
*,
*:before,
*:after {
#include box-sizing(border-box);
}
.rangeslider__value-bubble {
border: 1px solid #ccc;
display: block;
padding: 5px;
position: absolute;
bottom: 100%;
margin-bottom: 25px;
width: 100px;
margin-left: -50px;
text-align: center;
#include border-radius(5px);
font-family: "Lato", san-serif;
font-size: 13px;
&:before,
&:after {
border-width: 11px;
border-style: solid;
border-color: transparent;
content: "";
display: block;
margin: auto;
width: 10px;
position: absolute;
left: 0;
right: 0;
}
&:before {
border-top-color: #ccc;
border-bottom-width: 0;
bottom: -11px;
}
&:after {
border-top-color: #fff;
border-bottom-width: 0;
bottom: -10px;
}
}
<html>
<head>
<link href="https://cdnjs.cloudflare.com/ajax/libs/rangeslider.js/2.3.0/rangeslider.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Lato" rel="stylesheet">
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rangeslider.js/2.3.0/rangeslider.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.bundle.min.js"></script>
</head>
<main class="container">
<div class="sliderHolder">
<div class="wheelCat">Citizenship</div>
<div class="sliderAll">
<div class="sliderCitizenship">
<input type=range value=1 min=0 max=8 step=1 id="Citizenship">
</div>
</div>
<br>
<div class="wheelCat">People</div>
<div class="sliderAll">
<div class="sliderPeople">
<input type=range value=1 min=0 max=8 step=1 id="People">
</div>
</div>
<br>
<div class="wheelCat">Growth</div>
<div class="sliderAll">
<div class="sliderGrowth">
<input type=range value=1 min=0 max=8 step=1 id="Growth">
</div>
</div>
<br>
<div class="wheelCat">Management</div>
<div class="sliderAll">
<div class="sliderManagement">
<input type=range value=1 min=0 max=8 step=1 id="Management">
</div>
</div>
<br>
<div class="wheelCat">Relationships</div>
<div class="sliderAll">
<div class="sliderCitizenship">
<input type=range value=1 min=0 max=8 step=1 id="Citizenship">
</div>
</div>
<br>
<div class="wheelCat">Health</div>
<div class="sliderAll">
<div class="sliderHealth">
<input type=range value=1 min=0 max=8 step=1 id="Health">
</div>
</div>
<br>
<div class="wheelCat">Wealth</div>
<div class="sliderAll">
<div class="sliderWealth">
<input type=range value=1 min=0 max=8 step=1 id="Wealth">
</div>
</div>
<br>
<div class="wheelCat">Joy</div>
<div class="sliderAll">
<div class="sliderJoy">
<input type=range value=1 min=0 max=8 step=1 id="Joy">
</div>
</div>
<br>
</div>
<div style="float:left;width:80%;">
<canvas id="polarChart"></canvas>
</div>
</main>
</html>
This is where the problem sits:
updateChart(0, value);
this is responsible for updating data in data array position 0. When you change it to updateChart(1, value); it will update People category data. Change your code so the parameter is set dynamically based on the clicked slider.
--== UPDATE BELOW ==--
Looking up the code I found identifier for rangeSlider. Which suits perfectly for your case.
I do not know if this is correct way of passing this information, but it seems to be working.
Use updateChart(this.identifier.slice(-1), value);
Quick explanation - each object has got identifier such as
identifier : "js-rangeslider-0"
so I am taking current object (this), going inside .identifier and taking last character of this string .slice(-1).