Angular How to toggle the color of a button which is inside a button group if it is clicked? - twitter-bootstrap-3

I have a group of buttons in an angular 6 component:
<div class="container">
<div class="row">
<div class="clearfix text-center" [hidden]="!searchTerm">
<span class="inline">Filter results by :</span>
<div class="float-right">
<button type="submit" class="btn btn-primary" (click)="performSearch(searchTerm)">All</button>
<button type="submit" class="btn btn-secondary" (click)="domainesFilter(searchTerm)">Domaines</button>
<button type="submit" class="btn btn-secondary" (click)="sectionsFilter(searchTerm)">Sections</button>
<button type="submit" class="btn btn-secondary" (click)="groupsFilter(searchTerm)">Groups</button>
<button type="submit" class="btn btn-secondary" (click)="documentFilter(searchTerm)">Documents</button>
</div>
</div>
</div>
</div>
I want to change the color of the button to primary if it is clicked and set the color of the other buttons to secondary, how can I achieve that?

You can do something like this:
Component ts
#Component({
selector: 'app-my',
templateUrl: './my.component.html',
styleUrls: ['./my.component.css']
})
export class MyComponent implements OnInit {
selBtn: string;
constructor() { }
ngOnInit() {
}
performA(): void {
this.selBtn = 'a';
}
performB(): void {
this.selBtn = 'b';
}
performC(): void {
this.selBtn = 'c';
}
performD(): void {
this.selBtn = 'd';
}
performE(): void {
this.selBtn = 'e';
}
}
Template
<div class="container">
<div class="row">
<div class="clearfix text-center">
<span class="inline">Filter results by :</span>
<div class="float-right">
<button type="submit" class="btn {{ selBtn === 'a' ? 'btn-primary' : 'btn-secondary' }}" (click)="performA()">A</button>
<button type="submit" class="btn {{ selBtn === 'b' ? 'btn-primary' : 'btn-secondary' }}" (click)="performB()">B</button>
<button type="submit" class="btn {{ selBtn === 'c' ? 'btn-primary' : 'btn-secondary' }}" (click)="performC()">C</button>
<button type="submit" class="btn {{ selBtn === 'd' ? 'btn-primary' : 'btn-secondary' }}" (click)="performD()">D</button>
<button type="submit" class="btn {{ selBtn === 'e' ? 'btn-primary' : 'btn-secondary' }}" (click)="performE()">E</button>
</div>
</div>
</div>
</div>
Otherwise you could assign .btn-secondary to all your buttons, then adding btn-primary only if necessary like this:
<button type="submit" class="btn btn-secondary" [ngClass]="{'btn-primary' : selBtn === 'e'}" (click)="performE()">E</button>
With this solution you may need to adjust your css to be sure that btn-primary class overrides all of the properties of btn-secondary class

<div class="container">
<div class="row">
<div class="clearfix text-center" >
<span class="inline">Filter results by :</span>
<div class="float-right">
<button type="submit" class="btn" [ngClass]="{'btn-primary':ActiveButton=='All', 'btn-secondary':ActiveButton!='All'}" (click)="Search(searchTerm, 'All')">All</button>
<button type="submit" class="btn" [ngClass]="{'btn-primary':ActiveButton=='Domaines', 'btn-secondary':ActiveButton!='Domaines'}" (click)="Search(searchTerm, 'Domaines')">Domaines</button>
<button type="submit" class="btn" [ngClass]="{'btn-primary':ActiveButton=='Sections', 'btn-secondary':ActiveButton!='Sections'}" (click)="Search(searchTerm, 'Sections')">Sections</button>
<button type="submit" class="btn" [ngClass]="{'btn-primary':ActiveButton=='Groups', 'btn-secondary':ActiveButton!='Groups'}" (click)="Search(searchTerm, 'Groups')">Groups</button>
<button type="submit" class="btn" [ngClass]="{'btn-primary':ActiveButton=='Documents', 'btn-secondary':ActiveButton!='Documents'}" (click)="Search(searchTerm, 'Documents')">Documents</button>
</div>
</div>
</div>
</div>
And js code is like this.
Search(searchTerm, btn) {
this.ActiveButton = btn;
switch ( btn ) {
case 'All':
console.log('All');
break;
case 'Domaines':
console.log('Domaines');
break;
case 'Sections':
console.log('Sections');
break;
case 'Groups':
console.log('Groups');
break;
case 'Documents':
console.log('Documents');
break;
}
}

Related

Vue.js 2 components data property bound to the first or to one only instance of component

Need help. I'm fairly new to Vue.js and need some help and advice.
Context:
I have a component with BS modal inside which is rendered in a for loop and obviously has many instances.
Issue:
The very first rendered component has its data received from parent via props, and the rest component have their own (like row.id and etc.)
Question: How to fix it? Maybe the problem in BS modal?
Component:
let vSelect = Vue.component("v-select", VueSelect.VueSelect);
var scoringButton = Vue.component("scoring-button", {
props: ["loadId", "causeData"],
template: "#scoring-template",
components: {
"v-select": vSelect,
},
data: function () {
return {
scoredLoadId: this.loadId,
scoring: null,
causeId: null,
selectedCause: null,
causeList: this.causeData,
};
},
computed: {
showCauseList() {
if (this.scoring === "1" || this.scoring === null) {
return true;
}
return false;
},
},
});
Template:
<template v-cloak id="scoring-template">
<div class="scoring-block" :id="scoredLoadId">
<div class="scoring">
<button
v-if="scoring === '1'"
title="Scoring button"
type="button"
class="btn btn-success scoring-btn"
data-bs-toggle="modal"
data-bs-target="#scoringModal"
>
<i class="bi bi-hand-thumbs-up-fill"></i>
</button>
<button
v-else-if="scoring === '2'"
title="Scoring button"
type="button"
class="btn btn-danger scoring-btn"
data-bs-toggle="modal"
data-bs-target="#scoringModal"
>
<i class="bi bi-hand-thumbs-down-fill"></i>
</button>
<button
v-else
title="Scoring button"
type="button"
class="btn btn-info scoring-btn"
data-bs-toggle="modal"
data-bs-target="#scoringModal"
>
<i class="bi bi-hand-thumbs-up-fill"></i>
<i class="bi bi-hand-thumbs-down-fill"></i>
</button>
</div>
<div
class="modal fade scoring-modal"
id="scoringModal"
tabindex="-1"
role="dialog"
aria-hidden="true"
>
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content" :key="loadId">
<div class="modal-header">
<h1 class="modal-title">Load Scoring</h1>
<button
type="button"
class="btn-close"
aria-label="Close"
data-bs-dismiss="modal"
></button>
</div>
<div class="modal-body">
<div class="scoring-content">
<input
type="radio"
class="btn-check"
name="btnScore"
id="btnLike"
autocomplete="off"
checked="scoring === '1'"
value="1"
v-model="scoring"
/>
<label
class="btn btn-outline-success"
for="btnLike"
#click="clearSelectedCause"
>
<i class="bi bi-hand-thumbs-up-fill"></i> Like
</label>
<input
type="radio"
class="btn-check"
name="btnScore"
id="btnDislike"
autocomplete="off"
:checked="scoring === '2'"
value="2"
v-model="scoring"
/>
<label class="btn btn-outline-danger" for="btnDislike">
<i class="bi bi-hand-thumbs-down-fill"></i> Dislike
</label>
</div>
<div class="scoring-cause">
<v-select
:disabled="showCauseList"
label="name"
:options="causeList"
v-model="selectedCause"
placeholder="Choose a cause option"
></v-select>
</div>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-secondary"
data-bs-dismiss="modal"
>
Close
</button>
<button type="button" class="btn btn-primary">
Save changes
</button>
</div>
</div>
</div>
</div>
</div>
</template>
Parent:
var mainTableApp = new Vue({
el: "#main-table",
data: {
tableData: [],
scoringCauseList: [
{
"id": 6,
"scoring_type": 0,
"name": "Late at loading",
"mark": "late_at_loading"
},
{
"id": 7,
"scoring_type": 0,
"name": "Special conditions were not respected",
"mark": "special_conditions_were_not_respected"
},
{
"id": 8,
"scoring_type": 0,
"name": "Bad/not enough information",
"mark": "bad_not_enough_information"
}
],
},
components:{
'scoring-button': scoringButton,
}
});
Component in the main app block:
<div
v-for="row in tableData"
class="row-container"
>
....
<scoring-button
:id="row.LOAD_ID"
:key="row.LOAD_ID"
:load-id="row.LOAD_ID"
:cause-data="scoringCauseList"
>
</scoring-button>
....
</div>
I tried to resetting BS modal's data, but it didn't work. So, I went back to look for a solution in Vue part.
I know I may construct the whole thing not enough in a very right way, but this code below is the last version after many other solutions, have been tried with v-model, $emit, props etc.
Update: found solution.
Added ":id" for all "input" fields I had in my component.
So, to have reusable components their own data properties you need to have dynamic ":id" properties. So, that each data flows into their own component.
<input
type="radio"
class="btn-check"
name="btnScore"
id="btnLike" // <-- old line
:id="`btnLike-${dynamicStr}`" // <-- new modified line
autocomplete="off"
checked="scoring === '1'"
value="1"
v-model="scoring"
/>
<label
class="btn btn-outline-success"
for="btnLike" // <-- old line
:for="'btnLike-${dynamicStr}'" // <-- new modified line
#click="clearSelectedCause"
>
<i class="bi bi-hand-thumbs-up-fill"></i> Like
</label>

The below given code is not working for me. And giving an error "vueuploadComponent.html:396 Uncaught ReferenceError: FileUpload is not defined"

Here is the code in vue.js for multi Image uploading. Actually this code is not working for me I am facing an error "vueuploadComponent.html:396 Uncaught ReferenceError: FileUpload is not defined". So here I thing i doing some thing wrong with import a module. So please let me know where I am going wrong.
<template>
<div id = "vueUpload" class="example-full">
<button type="button" class="btn btn-danger float-right btn-is-option" #click.prevent="isOption = !isOption">
<i class="fa fa-cog" aria-hidden="true"></i>
Options
</button>
<h1 id="example-title" class="example-title">Full Example</h1>
<div v-show="$refs.upload && $refs.upload.dropActive" class="drop-active">
<h3>Drop files to upload</h3>
</div>
<div class="upload" v-show="!isOption">
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>#</th>
<th>Thumb</th>
<th>Name</th>
<th>Width</th>
<th>Height</th>
<th>Size</th>
<th>Speed</th>
<th>Status</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr v-if="!files.length">
<td colspan="9">
<div class="text-center p-5">
<h4>Drop files anywhere to upload<br/>or</h4>
<label :for="name" class="btn btn-lg btn-primary">Select Files</label>
</div>
</td>
</tr>
<tr v-for="(file, index) in files" :key="file.id">
<td>{{index}}</td>
<td>
<img class="td-image-thumb" v-if="file.thumb" :src="file.thumb" />
<span v-else>No Image</span>
</td>
<td>
<div class="filename">
{{file.name}}
</div>
<div class="progress" v-if="file.active || file.progress !== '0.00'">
<div :class="{'progress-bar': true, 'progress-bar-striped': true, 'bg-danger': file.error, 'progress-bar-animated': file.active}" role="progressbar" :style="{width: file.progress + '%'}">{{file.progress}}%</div>
</div>
</td>
<td>{{file.width || 0}}</td>
<td>{{file.height || 0}}</td>
<td>{{$formatSize(file.size)}}</td>
<td>{{$formatSize(file.speed)}}</td>
<td v-if="file.error">{{file.error}}</td>
<td v-else-if="file.success">success</td>
<td v-else-if="file.active">active</td>
<td v-else></td>
<td>
<div class="btn-group">
<button class="btn btn-secondary btn-sm dropdown-toggle" type="button">
Action
</button>
<div class="dropdown-menu">
<a :class="{'dropdown-item': true, disabled: file.active || file.success || file.error === 'compressing' || file.error === 'image parsing'}" href="#" #click.prevent="file.active || file.success || file.error === 'compressing' ? false : onEditFileShow(file)">Edit</a>
<a :class="{'dropdown-item': true, disabled: !file.active}" href="#" #click.prevent="file.active ? $refs.upload.update(file, {error: 'cancel'}) : false">Cancel</a>
<a class="dropdown-item" href="#" v-if="file.active" #click.prevent="$refs.upload.update(file, {active: false})">Abort</a>
<a class="dropdown-item" href="#" v-else-if="file.error && file.error !== 'compressing' && file.error !== 'image parsing' && $refs.upload.features.html5" #click.prevent="$refs.upload.update(file, {active: true, error: '', progress: '0.00'})">Retry upload</a>
<a :class="{'dropdown-item': true, disabled: file.success || file.error === 'compressing' || file.error === 'image parsing'}" href="#" v-else #click.prevent="file.success || file.error === 'compressing' || file.error === 'image parsing' ? false : $refs.upload.update(file, {active: true})">Upload</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" #click.prevent="$refs.upload.remove(file)">Remove</a>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div class="example-foorer">
<div class="footer-status float-right">
Drop: {{$refs.upload ? $refs.upload.drop : false}},
Active: {{$refs.upload ? $refs.upload.active : false}},
Uploaded: {{$refs.upload ? $refs.upload.uploaded : true}},
Drop active: {{$refs.upload ? $refs.upload.dropActive : false}}
</div>
<div class="btn-group">
<file-upload
class="btn btn-primary dropdown-toggle"
:post-action="postAction"
:put-action="putAction"
:extensions="extensions"
:accept="accept"
:multiple="multiple"
:directory="directory"
:create-directory="createDirectory"
:size="size || 0"
:thread="thread < 1 ? 1 : (thread > 5 ? 5 : thread)"
:headers="headers"
:data="data"
:drop="drop"
:drop-directory="dropDirectory"
:add-index="addIndex"
v-model="files"
#input-filter="inputFilter"
#input-file="inputFile"
ref="upload">
<i class="fa fa-plus"></i>
Select
</file-upload>
<div class="dropdown-menu">
<label class="dropdown-item" :for="name">Add files</label>
<a class="dropdown-item" href="#" #click="onAddFolder">Add folder</a>
<a class="dropdown-item" href="#" #click.prevent="addData.show = true">Add data</a>
</div>
</div>
<button type="button" class="btn btn-success" v-if="!$refs.upload || !$refs.upload.active" #click.prevent="$refs.upload.active = true">
<i class="fa fa-arrow-up" aria-hidden="true"></i>
Start Upload
</button>
<button type="button" class="btn btn-danger" v-else #click.prevent="$refs.upload.active = false">
<i class="fa fa-stop" aria-hidden="true"></i>
Stop Upload
</button>
</div>
</div>
<div class="option" v-show="isOption">
<div class="form-group">
<label for="accept">Accept:</label>
<input type="text" id="accept" class="form-control" v-model="accept">
<small class="form-text text-muted">Allow upload mime type</small>
</div>
<div class="form-group">
<label for="extensions">Extensions:</label>
<input type="text" id="extensions" class="form-control" v-model="extensions">
<small class="form-text text-muted">Allow upload file extension</small>
</div>
<div class="form-group">
<label>PUT Upload:</label>
<div class="form-check">
<label class="form-check-label">
<input class="form-check-input" type="radio" name="put-action" id="put-action" value="" v-model="putAction"> Off
</label>
</div>
<div class="form-check">
<label class="form-check-label">
<input class="form-check-input" type="radio" name="put-action" id="put-action" value="/upload/put" v-model="putAction"> On
</label>
</div>
<small class="form-text text-muted">After the shutdown, use the POST method to upload</small>
</div>
<div class="form-group">
<label for="thread">Thread:</label>
<input type="number" max="5" min="1" id="thread" class="form-control" v-model.number="thread">
<small class="form-text text-muted">Also upload the number of files at the same time (number of threads)</small>
</div>
<div class="form-group">
<label for="size">Max size:</label>
<input type="number" min="0" id="size" class="form-control" v-model.number="size">
</div>
<div class="form-group">
<label for="minSize">Min size:</label>
<input type="number" min="0" id="minSize" class="form-control" v-model.number="minSize">
</div>
<div class="form-group">
<label for="autoCompress">Automatically compress:</label>
<input type="number" min="0" id="autoCompress" class="form-control" v-model.number="autoCompress">
<small class="form-text text-muted" v-if="autoCompress > 0">More than {{$formatSize(autoCompress)}} files are automatically compressed</small>
<small class="form-text text-muted" v-else>Set up automatic compression</small>
</div>
<div class="form-group">
<div class="form-check">
<label class="form-check-label">
<input type="checkbox" id="add-index" class="form-check-input" v-model="addIndex"> Start position to add
</label>
</div>
<small class="form-text text-muted">Add a file list to start the location to add</small>
</div>
<div class="form-group">
<div class="form-check">
<label class="form-check-label">
<input type="checkbox" id="drop" class="form-check-input" v-model="drop"> Drop
</label>
</div>
<small class="form-text text-muted">Drag and drop upload</small>
</div>
<div class="form-group">
<div class="form-check">
<label class="form-check-label">
<input type="checkbox" id="drop-directory" class="form-check-input" v-model="dropDirectory"> Drop directory
</label>
</div>
<small class="form-text text-muted">Not checked, filter the dragged folder</small>
</div>
<div class="form-group">
<div class="form-check">
<label class="form-check-label">
<input type="checkbox" id="create-directory" class="form-check-input" v-model="createDirectory"> Create Directory
</label>
</div>
<small class="form-text text-muted">The directory file will send an upload request. The mime type is <code>text/directory</code></small>
</div>
<div class="form-group">
<div class="form-check">
<label class="form-check-label">
<input type="checkbox" id="upload-auto" class="form-check-input" v-model="uploadAuto"> Auto start
</label>
</div>
<small class="form-text text-muted">Automatically activate upload</small>
</div>
<div class="form-group">
<button type="button" class="btn btn-primary btn-lg btn-block" #click.prevent="isOption = !isOption">Confirm</button>
</div>
</div>
<div :class="{'modal-backdrop': true, 'fade': true, show: addData.show}"></div>
<div :class="{modal: true, fade: true, show: addData.show}" id="modal-add-data" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Add data</h5>
<button type="button" class="close" #click.prevent="addData.show = false">
<span>×</span>
</button>
</div>
<form #submit.prevent="onAddData">
<div class="modal-body">
<div class="form-group">
<label for="data-name">Name:</label>
<input type="text" class="form-control" required id="data-name" placeholder="Please enter a file name" v-model="addData.name">
<small class="form-text text-muted">Such as <code>filename.txt</code></small>
</div>
<div class="form-group">
<label for="data-type">Type:</label>
<input type="text" class="form-control" required id="data-type" placeholder="Please enter the MIME type" v-model="addData.type">
<small class="form-text text-muted">Such as <code>text/plain</code></small>
</div>
<div class="form-group">
<label for="content">Content:</label>
<textarea class="form-control" required id="content" rows="3" placeholder="Please enter the file contents" v-model="addData.content"></textarea>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" #click.prevent="addData.show = false">Close</button>
<button type="submit" class="btn btn-primary">Save</button>
</div>
</form>
</div>
</div>
</div>
<div :class="{'modal-backdrop': true, 'fade': true, show: editFile.show}"></div>
<div :class="{modal: true, fade: true, show: editFile.show}" id="modal-edit-file" tabindex="-1" role="dialog">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Edit file</h5>
<button type="button" class="close" #click.prevent="editFile.show = false">
<span>×</span>
</button>
</div>
<form #submit.prevent="onEditorFile">
<div class="modal-body">
<div class="form-group">
<label for="name">Name:</label>
<input type="text" class="form-control" required id="name" placeholder="Please enter a file name" v-model="editFile.name">
</div>
<div class="form-group" v-if="editFile.show && editFile.blob && editFile.type && editFile.type.substr(0, 6) === 'image/'">
<label>Image: </label>
<div class="edit-image">
<img :src="editFile.blob" ref="editImage" />
</div>
<div class="edit-image-tool">
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary" #click="editFile.cropper.rotate(-90)" title="cropper.rotate(-90)"><i class="fa fa-undo" aria-hidden="true"></i></button>
<button type="button" class="btn btn-primary" #click="editFile.cropper.rotate(90)" title="cropper.rotate(90)"><i class="fa fa-repeat" aria-hidden="true"></i></button>
</div>
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary" #click="editFile.cropper.crop()" title="cropper.crop()"><i class="fa fa-check" aria-hidden="true"></i></button>
<button type="button" class="btn btn-primary" #click="editFile.cropper.clear()" title="cropper.clear()"><i class="fa fa-remove" aria-hidden="true"></i></button>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" #click.prevent="editFile.show = false">Close</button>
<button type="submit" class="btn btn-primary">Save</button>
</div>
</form>
</div>
</div>
</div>
</div>
</template>
<script src='https://unpkg.com/vue#2.5.16/dist/vue.js'></script>
<script type="module">
import Cropper from 'cropperjs'
import ImageCompressor from '#xkeshi/image-compressor'
import { FileUpload } from "vue-upload-component";
</script>
<script>
new Vue({
el: '#vueUpload',
components: {
FileUpload,
},
data() {
return {
files: [],
accept: 'image/png,image/gif,image/jpeg,image/webp',
extensions: 'gif,jpg,jpeg,png,webp',
// extensions: ['gif', 'jpg', 'jpeg','png', 'webp'],
// extensions: /\.(gif|jpe?g|png|webp)$/i,
minSize: 1024,
size: 1024 * 1024 * 10,
multiple: true,
directory: false,
drop: true,
dropDirectory: true,
createDirectory: false,
addIndex: false,
thread: 3,
name: 'file',
postAction: '/upload/post',
putAction: '/upload/put',
headers: {
'X-Csrf-Token': 'xxxx',
},
data: {
'_csrf_token': 'xxxxxx',
},
autoCompress: 1024 * 1024,
uploadAuto: false,
isOption: false,
addData: {
show: false,
name: '',
type: '',
content: '',
},
editFile: {
show: false,
name: '',
}
}
},
watch: {
'editFile.show'(newValue, oldValue) {
// 关闭了 自动删除 error
if (!newValue && oldValue) {
this.$refs.upload.update(this.editFile.id, { error: this.editFile.error || '' })
}
if (newValue) {
this.$nextTick( () => {
if (!this.$refs.editImage) {
return
}
let cropper = new Cropper(this.$refs.editImage, {
autoCrop: false,
})
this.editFile = {
...this.editFile,
cropper
}
})
}
},
'addData.show'(show) {
if (show) {
this.addData.name = ''
this.addData.type = ''
this.addData.content = ''
}
},
},
methods: {
inputFilter(newFile, oldFile, prevent) {
if (newFile && !oldFile) {
// Before adding a file
// 添加文件前
// Filter system files or hide files
// 过滤系统文件 和隐藏文件
if (/(\/|^)(Thumbs\.db|desktop\.ini|\..+)$/.test(newFile.name)) {
return prevent()
}
// Filter php html js file
// 过滤 php html js 文件
if (/\.(php5?|html?|jsx?)$/i.test(newFile.name)) {
return prevent()
}
// Automatic compression
// 自动压缩
if (newFile.file && newFile.error === "" && newFile.type.substr(0, 6) === 'image/' && this.autoCompress > 0 && this.autoCompress < newFile.size) {
newFile.error = 'compressing'
const imageCompressor = new ImageCompressor(null, {
convertSize: 1024 * 1024,
maxWidth: 512,
maxHeight: 512,
})
imageCompressor.compress(newFile.file)
.then((file) => {
this.$refs.upload.update(newFile, { error: '', file, size: file.size, type: file.type })
})
.catch((err) => {
this.$refs.upload.update(newFile, { error: err.message || 'compress' })
})
}
}
if (newFile && newFile.error === "" && newFile.file && (!oldFile || newFile.file !== oldFile.file)) {
// Create a blob field
// 创建 blob 字段
newFile.blob = ''
let URL = (window.URL || window.webkitURL)
if (URL) {
newFile.blob = URL.createObjectURL(newFile.file)
}
// Thumbnails
// 缩略图
newFile.thumb = ''
if (newFile.blob && newFile.type.substr(0, 6) === 'image/') {
newFile.thumb = newFile.blob
}
}
// image size
// image 尺寸
if (newFile && newFile.error === '' && newFile.type.substr(0, 6) === "image/" && newFile.blob && (!oldFile || newFile.blob !== oldFile.blob)) {
newFile.error = 'image parsing'
let img = new Image();
img.onload = () => {
this.$refs.upload.update(newFile, {error: '', height: img.height, width: img.width})
}
img.οnerrοr = (e) => {
this.$refs.upload.update(newFile, { error: 'parsing image size'})
}
img.src = newFile.blob
}
},
// add, update, remove File Event
inputFile(newFile, oldFile) {
if (newFile && oldFile) {
// update
if (newFile.active && !oldFile.active) {
// beforeSend
// min size
if (newFile.size >= 0 && this.minSize > 0 && newFile.size < this.minSize) {
this.$refs.upload.update(newFile, { error: 'size' })
}
}
if (newFile.progress !== oldFile.progress) {
// progress
}
if (newFile.error && !oldFile.error) {
// error
}
if (newFile.success && !oldFile.success) {
// success
}
}
if (!newFile && oldFile) {
// remove
if (oldFile.success && oldFile.response.id) {
// $.ajax({
// type: 'DELETE',
// url: '/upload/delete?id=' + oldFile.response.id,
// })
}
}
// Automatically activate upload
if (Boolean(newFile) !== Boolean(oldFile) || oldFile.error !== newFile.error) {
if (this.uploadAuto && !this.$refs.upload.active) {
this.$refs.upload.active = true
}
}
},
alert(message) {
alert(message)
},
onEditFileShow(file) {
this.editFile = { ...file, show: true }
this.$refs.upload.update(file, { error: 'edit' })
},
onEditorFile() {
if (!this.$refs.upload.features.html5) {
this.alert('Your browser does not support')
this.editFile.show = false
return
}
let data = {
name: this.editFile.name,
error: '',
}
if (this.editFile.cropper) {
let binStr = atob(this.editFile.cropper.getCroppedCanvas().toDataURL(this.editFile.type).split(',')[1])
let arr = new Uint8Array(binStr.length)
for (let i = 0; i < binStr.length; i++) {
arr[i] = binStr.charCodeAt(i)
}
data.file = new File([arr], data.name, { type: this.editFile.type })
data.size = data.file.size
}
this.$refs.upload.update(this.editFile.id, data)
this.editFile.error = ''
this.editFile.show = false
},
// add folder
onAddFolder() {
if (!this.$refs.upload.features.directory) {
this.alert('Your browser does not support')
return
}
let input = document.createElement('input')
input.style = "background: rgba(255, 255, 255, 0);overflow: hidden;position: fixed;width: 1px;height: 1px;z-index: -1;opacity: 0;"
input.type = 'file'
input.setAttribute('allowdirs', true)
input.setAttribute('directory', true)
input.setAttribute('webkitdirectory', true)
input.multiple = true
document.querySelector("body").appendChild(input)
input.click()
input.onchange = (e) => {
this.$refs.upload.addInputFile(input).then(function() {
document.querySelector("body").removeChild(input)
})
}
},
onAddData() {
this.addData.show = false
if (!this.$refs.upload.features.html5) {
this.alert('Your browser does not support')
return
}
let file = new window.File([this.addData.content], this.addData.name, {
type: this.addData.type,
})
this.$refs.upload.add(file)
}
}
})
</script>
Assuming you're using Lian Yue's vue-upload-component and have installed it successfully, try removing the curly braces from your import:
import FileUpload from "vue-upload-component";
This will set FileUpload to the default export from vue-upload-component which I believe is what you want

Nuxt component variable not updated

I wrote the following code for my navbar:
<template>
<div>
<div v-if="!$auth.loggedIn" data-tip="Login" class="tooltip tooltip-bottom">
<nuxt-link to="/login" class="btn btn-square btn-ghost">
<solid-login-icon class="w-6 h-6" />
</nuxt-link>
</div>
<div v-else class="flex items-stretch">
<a class="pr-2 btn btn-ghost rounded-btn"> Welcome, {{ this.$auth.user.username }}! 👋 </a>
<div data-tip="Logout" class="tooltip tooltip-bottom">
<button class="pr-2 btn btn-square btn-ghost" #click="logout()">
<solid-login-icon class="w-6 h-6" />
</button>
</div>
</div>
</div>
</template>
Which is include in the following login page:
<template>
<div class="h-screen shadow bg-base-200 drawer drawer-mobile">
<input id="my-drawer-2" type="checkbox" class="drawer-toggle" />
<div class="drawer-content">
<NavBar />
<div class="grid grid-cols-1 p-5 md:grid-cols-6">
<div class="col-span-1 md:col-span-2 md:col-start-3">
<div class="bg-white shadow card">
<div class="card-body">
<h2 class="text-left card-title">Login</h2>
<form #submit.prevent="userLogin">
<div class="form-control">
<label class="label">
<span class="label-text">Username</span>
</label>
<input
v-model="login.username"
type="text"
placeholder="Username"
class="input input-bordered"
/>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">Username</span>
</label>
<input
v-model="login.password"
type="password"
placeholder="Password"
class="input input-bordered"
/>
</div>
<div class="mt-4">
<button type="submit" class="btn btn-primary btn-md">Login</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<SideBar />
</div>
</template>
<script>
export default {
data() {
return {
login: {
username: '',
password: '',
},
}
},
methods: {
async userLogin() {
try {
const response = await this.$auth.loginWith('local', { data: this.login })
} catch (err) {}
},
},
}
</script>
Upon loggin in with correct credentials the page keeps dispalying the "Login"-icon instead of the Welcome message.
I've tried to replace !$auth.loggedIn with loggedIn (coming from the data function) and with !this.$auth.loggedIn" but both don't seem to solve the issue

How to focus click on input vue

how do i focus input with a button onClick?
<div class="form-group"
v-for="(file, i) in registerData.requiredDocuments"
:key="`file-${i}`">
<label for="npwp" class="text-muted"> {{file.name}} </label>
<input type="file"
:name="file.name"
class="form-control-file"
:id="file.name"
:accept="file.name === 'Logo' ? `image/png, image/jpg, image/jpeg` : `application/pdf`">
<div class="d-flex">
<button class="btn btn-primary" type="button">Choose File</button>
</div>
</div>
i was hoping by clicking the 'choose file' button it would trigger the input. I've tried
// the input
<input :ref="file.name" type="file">
// the button
<button #click="$refs.file.name.focus()">Choose File</button>
but what i get is the name is undefined anyone knows how to fix this?
I had similar problem before, Here is how and did it.
<template>
<div>
<div class="form-group" v-for="(file, i) in registerData.requiredDocuments" :key="`file-${i}`">
<label for="npwp" class="text-muted"> {{file.name}} </label>
<input type="file" :ref="'file' + i" :name="file.name" class="form-control-file" :id="file.name"
:accept="file.name === 'Logo' ? `image/png, image/jpg, image/jpeg` : `application/pdf`">
<div class="d-flex">
<button #click.prevent="setFileFocus(i)" class="btn btn-primary" type="button">Choose File</button>
</div>
</div>
</div>
</template>
<script>
export default {
methods: {
setFileFocus(index) {
this.$nextTick(function(){
this.$refs[("file" + index)][0].focus()
})
}
}
}
</script>
I called focus on nexttick. Hope my answer will be helpful

Angular2 typescript set selected dropdown button value on page load

Ref : trying to use Dropdown component https://github.com/valor-software/ng2-bootstrap/tree/development/components/dropdown
I can pull the drop down values on clicking button and persist on selection using Typescript but couldn't set the selected value on page load like we do using select option like :
<option [selected]="value.id == value.statusId">
Parent template :
<dropdownst [values]="releaseNames" [selectedReleaseId]="item.releaseId"></dropdownst>
Object : releaseName.ts
export class ReleaseName {
releaseId: number;
name: string;
}
Dropdown Component :
#Component({
selector: 'dropdownst',
template: `<div (click)="$event.preventDefault()">
<div>
<button type="button" class="btn btn-warning btn-sm" (click)="dropdownMenu($event)">
RELEASE (Toggle)
</button>
</div>
<div class="btn-group" dropdown [(isOpen)]="status.isopen">
<button id="dropdown-list" class="btn btn-default" dropdownToggle >
{{title}}
<span class="caret"></span>
</button>
<ul class="dropdown-menu scrollable-menu" role="menu" aria-labelledby="dropdown-list">
<li role="menuitem" *ngFor="let data of values">
<a class="dropdown-item" [id]="data.releaseId" #val [title]="data.name"
(click)="updatePbiRelease(val.id, val.title)" >
{{data.name}}
</a>
</li>
</ul>
</div>
</div> `,
directives: [ DropdownDirective, DropdownMenuDirective, DropdownToggleDirective, CORE_DIRECTIVES],
styles:['.scrollable-menu {height: auto;max-height: 200px;overflow-x: hidden;}']
})
export class Angular2Dropdown implements OnInit{
#Input()
selectedReleaseId: number;
#Input()
values: ReleaseName[];
#Input()
title: string;
private disabledMenu:boolean = false;
appComponent: AppComponent;
private status:{isopen:boolean} = {isopen: false};
constructor(#Inject(forwardRef(() => AppComponent)) private _parent:AppComponent){
this.appComponent = _parent;
}
updatePbiRelease(releaseValue, title){
this.appComponent.updatePbiRelease(releaseValue);
this.title = title;
}
private dropdownMenu($event:MouseEvent):void {
$event.preventDefault();
$event.stopPropagation();
this.status.isopen = !this.status.isopen;
}
ngOnInit() {
}
}
Html Template :
<div (click)="$event.preventDefault()">
<div>
<button type="button" class="btn btn-warning btn-sm" (click)="dropdownMenu($event)">
RELEASE (Toggle)
</button>
</div>
<div class="btn-group" dropdown [(isOpen)]="status.isopen">
<button id="dropdown-list" class="btn btn-default" dropdownToggle >
//Trying to set dropdown selected value here on page load as title from DB on TS Angular 2
{{title}}
<span class="caret"></span>
</button>
<ul class="dropdown-menu scrollable-menu" role="menu" aria-labelledby="dropdown-list">
//Iterate through releaseName has values passed from parent template
//to get name (i.e title) matchng releaseId and Id from DB(i.e item.releaseId)
<li role="menuitem" *ngFor="let data of values">
<a class="dropdown-item" [id]="data.releaseId" #val [title]="data.releaseId == selectedReleaseId ? data.name : data.name"
(click)="updatePbiRelease(val.id, val.title)" >
{{data.name}}
</a>
</li>
</ul>
</div>
Any help would be great.
Did the following changes to Template and ngOnInit() to work
Template :
template: `<div (click)="$event.preventDefault()">
<div>
<button type="button" class="btn btn-warning btn-sm" (click)="dropdownMenu($event)">
RELEASE (Toggle)
</button>
</div>
<div class="btn-group" dropdown [(isOpen)]="status.isopen">
<button id="dropdown-list" class="btn btn-default" dropdownToggle >
{{title}}
<span class="caret"></span>
</button>
<ul class="dropdown-menu scrollable-menu" role="menu" aria-labelledby="dropdown-list">
<li role="menuitem" *ngFor="let data of values">
<a class="dropdown-item" [id]="data.releaseId" #val [title]="data.name"
(click)="updatePbiRelease(val.id, val.title)" >
{{data.name}}
</a>
</li>
</ul>
</div>
</div> `,
Added a if condition on releaseName on parent template
<dropdown *ngIf="releaseNames" [values]="releaseNames" [selectedReleaseId]="item.releaseId">
Set the title value on page load onInit using the id passed from parent template selectedReleaseId
ngOnInit() {
for (var x = 0; x < this.values.length; x++) {
if(this.values[x].releaseId == this.selectedReleaseId) {
this.title = this.values[x].name;
}
}
}