Reputation: 5367
I'm doing a "status update" component of sorts, in my actual component I'm marking the first custom checkbox (the circles at top, etc.) as checked
...but for the CodePen below, I just marked them all as :checked='false'
to iterate my issue.
The "twitter" checkboxes won't check and uncheck. The Facebook ones will.
I'm certain this has to do with the fact that I'm enabling/disabling a character counter on the twitter checkboxes. If you click one of the twitter checkboxes, you'll notice the character counter turn on, but the checkbox is never checked (or rather, is checked then immediately unchecked)...
For example, in the method toggleMaxCharLength()
, if I comment out self.enableMaxCharLength = true;
, the checkbox work as they should.
If I remove the :checked='false'
from the input v-for
, works as it should...
UPDATE - WORKING PEN AND SOLUTION: https://codepen.io/mikebarwick/pen/qXdqBO
Upvotes: 2
Views: 1599
Reputation: 82449
Checking the twitter accounts causes a re-render, which, of course, sets your checked
value to false.
You need to remember the checked value. I made a couple small modifications that will do so, but there are other ways.
<input type="checkbox"
:ref="key"
:name="scheduleUsingBuffer ? 'buffer_profiles[]' : key + '[]'"
:value="scheduleUsingBuffer ? account.profile_id : account.page_id"
:checked="account.checked"
@change="handleAccountInputChange(key, account)">
And
handleAccountInputChange(type, account) {
this.$set(account, 'checked', !account.checked)
if (type == 'twitter') {
this.toggleMaxCharLength();
}
},
Another way to avoid this would be to abstract the checkboxes into their own components that remember their state so that when the parent re-renders, the state of the checkboxes is not overwritten.
Also, the pen converted into an SO snippet.
var accounts = {
facebook: {
testing1: {
page_id: '23derf56hg',
img_url: null
}
},
twitter: {
testing2: {
page_id: 'fr2wlfrhoi',
img_url: null
},
testing3: {
page_id: '92frgl5639',
img_url: null
}
}
}
var app = new Vue({
el: '#app',
mounted(){
setTimeout(() => {
Object.keys(accounts).forEach((site, siteIndex) => {
Object.keys(accounts[site]).forEach((account, actIndex) =>{
accounts[site][account]["checked"] = (siteIndex === 0 && actIndex === 0)
})
})
console.log(accounts)
this.connectedAccounts = accounts
}, 100)
},
data: {
message: 'Hello Vue!',
connectedAccounts: [],
scheduleUsingBuffer: false,
formData: {},
enableMaxCharLength: false,
maxCharCount: 140,
remainingCharCount: 140,
isAboveMaxCharCount: false,
statusMessage: ''
},
methods: {
onSubmit(event) {
this.formData = serialize(event.target, { hash: true });
},
toggleMaxCharLength() {
this.enableMaxCharLength = false;
Vue.nextTick(() => {
var self = this;
this.$refs.twitter.forEach(twitterInput => {
if (twitterInput.checked) {
self.enableMaxCharLength = true;
}
});
});
},
handleAccountInputChange(type, account) {
this.$set(account, 'checked', !account.checked)
if (type == 'twitter') {
this.toggleMaxCharLength();
}
},
countdown() {
this.remainingCharCount = this.maxCharCount - this.statusMessage.length;
this.isAboveMaxCharCount = this.remainingCharCount < 0;
}
}
})
section.create-story {
margin: 30px auto;
width: 425px;
}
section.create-story h4 {
margin-bottom: 15px;
letter-spacing: 0.1em;
text-transform: uppercase;
font-weight: normal;
font-size: 14px;
}
section.create-story .switch {
display: block;
margin-bottom: 20px;
}
section.create-story #connected-accounts {
margin-bottom: 15px;
}
section.create-story #connected-accounts label.account-checkbox {
position: relative;
display: inline-block;
margin: 0 5px 0px 0;
cursor: pointer;
}
section.create-story #connected-accounts label.account-checkbox .avatar {
position: relative;
width: 38px;
height: 38px;
border-radius: 50%;
background-size: cover !important;
background-position: center !important;
background-color: #CCC !important;
border: 2px solid #CCC;
transition: all 0.1s ease-in-out;
}
section.create-story #connected-accounts label.account-checkbox .avatar,
section.create-story #connected-accounts label.account-checkbox .account-icon {
filter: grayscale(100%);
opacity: 0.3;
}
section.create-story #connected-accounts label.account-checkbox .avatar:hover,
section.create-story #connected-accounts label.account-checkbox .account-icon:hover {
opacity: 1;
}
section.create-story #connected-accounts label.account-checkbox input[type="checkbox"] {
display: none;
}
section.create-story #connected-accounts label.account-checkbox input[type="checkbox"]:checked + .avatar {
border: 2px solid green;
}
section.create-story #connected-accounts label.account-checkbox input[type="checkbox"]:checked + .avatar + .account-icon {
color: green;
}
section.create-story #connected-accounts label.account-checkbox input[type="checkbox"]:checked + .avatar, section.create-story #connected-accounts label.account-checkbox input[type="checkbox"]:checked + .avatar + .account-icon {
filter: grayscale(0);
opacity: 1;
}
section.create-story #connected-accounts label.account-checkbox .account-icon {
position: absolute;
font-size: 13px;
width: 24px;
height: 24px;
line-height: 24px;
right: -4px;
bottom: -4px;
background: white;
color: #4d4d4d;
border-radius: 50%;
pointer-events: none;
box-shadow: 0 1px 0 0px rgba(49, 49, 93, 0.05), 0 2px 3px 0 rgba(49, 49, 93, 0.2), 0 1px 1px 0 rgba(0, 0, 0, 0.1);
}
section.create-story #status {
margin-bottom: 20px;
padding: 15px;
border-radius: 5px;
border: 1px solid #4d4d4d;
}
section.create-story #status textarea {
display: block;
margin-bottom: 15px;
padding: 0;
font-style: italic;
font-size: 14px;
min-height: 60px;
border: none;
box-shadow: none;
}
section.create-story #status .remaining-chars.has-text-danger {
font-weight: bold;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script>
<div id="app">
<section class="create-story box content">
<h4>New Story</h4>
<form id="new-story" v-on:submit.prevent="onSubmit">
<div id="status">
<div id="connected-accounts">
<span v-for="(accounts, key, index) in connectedAccounts">
<label v-for="(account, i) in accounts" class="account-checkbox">
<input type="checkbox"
:key="key"
:ref="key"
:name="scheduleUsingBuffer ? 'buffer_profiles[]' : key + '[]'"
:value="scheduleUsingBuffer ? account.profile_id : account.page_id"
:checked="account.checked"
@change="handleAccountInputChange(key, account)"> <!-- mark first account as "checked" :checked="index == 0 && i == 0" -->
<div
class="avatar"
:style="'background: url(' + account.img_url + ')'">
</div>
<i :class="'account-icon fa fa-' + key"></i>
</label>
</span>
</div>
<div class="control">
<textarea @keyup="countdown" v-model="statusMessage" name="status-message" class="textarea" placeholder="What story do you have to tell?"></textarea>
</div>
<div class="level">
<div class="level-right">
<div v-if="enableMaxCharLength" class="level-item">
<span :class="{'has-text-danger': isAboveMaxCharCount}" class="remaining-chars" v-text="remainingCharCount"></span>
</div>
<div class="level-item">
<input type="submit" value="Schedule" class="button is-primary">
</div>
</div>
</div>
</div>
</form>
</section>
</div>
Upvotes: 3