Vue-Select: How to save all entries as lower case items? - vuejs3

I am using the vue-select library. How can I force input entries to make all characters lower case? Right now, when I type the word "Baseball" into the input field, the tag is saved as "Baseball". I would like all tags to only keep a lower case version of the entry such as "baseball".
I have a sandbox here: https://stackblitz.com/edit/vue-ranqmt?file=src/App.vue
<template>
<div id="app">
<h3>Vue Select</h3>
<v-select
v-model="selected"
taggable
multiple
:options="options"
#input="setSelected"
></v-select>
<br /><br />
selected: <br />
<pre>{{ selected }}</pre>
</div>
</template>
<script>
import vSelect from 'vue-select';
import 'vue-select/dist/vue-select.css';
export default {
name: 'App',
components: {
'v-select': vSelect,
},
data() {
return {
selected: null,
options: [],
};
},
methods: {
setSelected(value) {
console.log(value);
},
},
};
</script>

a - You could add a computed property which returns the lowercased version to use in whichever part of your app you need it to be.
computed: {
selectedLowerCase() {
return this.selected.toLowerCase();
}
}
b - if you are using this for something like an API call, then you can turn the variable(s) into lowercase before submitting.
c - if you want the variable to appear as lowercase even in the input field you need to add the #input action to your input field and point it to a function to lowercase your input
methods: {
setSelected(value) {
this.selected = this.selected.toLowerCase();
console.log(value);
},
},

Related

Is there a way to use a prop as the site-key for vue-recaptcha?

I have a Form component in Vue where I import the vue-recaptcha like this:
<template>
... Contains the form and button that triggers onSubmit function
</template>
<script>
import { VueReCaptcha } from 'vue-recaptcha-v3';
Vue.use(VueReCaptcha, {
siteKey: "hard-coded site-key here",
loaderOptions: {
useRecaptchaNet: true,
},
});
export default {
methods: {
async onSubmit(e) {
// Uses the recapatcha and handles errors/success etc.
},
},
};
...
This works since the value for site-key is hard-coded.
However, I wish to be able to pass the site-key as a prop to the Form component and then use this as the site-key.
I tried something as bold as simply creating a prop in the Form component and passing it in as the site-key when setting the vue-recaptcha options, like this:
<script>
import { VueReCaptcha } from 'vue-recaptcha-v3';
Vue.use(VueReCaptcha, {
siteKey: this.siteKey,
loaderOptions: {
useRecaptchaNet: true,
},
});
export default {
props: {
siteKey: String,
},
...
</script>
This does not work because this.siteKey is undefined, as expected. However, is there a way to set the site-key value as the prop siteKey? Maybe there is a way to set the vue-recaptcha plugin options inside the component where this.siteKey isn't undefined, for example in mounted()?
Have you tried to provide the Key to the Form over prop?
<my-form siteKey="<My Site Key>" ...
or
<my-form site-key="<My Site Key>" ...
Pay attention:
You should be careful with components and prop's naming & using, since there are DOM
Template Parsing Caveats

Tailwind: How to create a loading: modifier/variant?

I'm trying to create a modifier for a button for when it's in a loading state.
Based on the documentation here, I added the following in my tailwind.config.js
// I assume this is included in tailwindcss
// and doesn't need to be installed separately
const plugin = require('tailwindcss/plugin')
module.exports = {
// ...
plugins: [
plugin(function({ addVariant }) {
addVariant('loading', '&:loading')
})
],
};
I assume this allows me to add a string of loading in the class such that it will apply those styles. This doesn't seem to work though, what am I doing wrong?
<!-- I assume this should be blue-600 -->
<button className="bg-blue-600 loading:bg-blue-100">
This is a normal button
</button>
<!-- I assume this should be blue-100 since it has className, "loading" -->
<button className="loading bg-blue-600 loading:bg-blue-100">
This is a loading button
</button>
& sign points to an element with THIS variant applied, so it should be translated in CSS as "this element with class .loading". In your example :loading will be translated as loading state which is not valid
So it should be addVariant('loading', '&.loading') not addVariant('loading', '&:loading')
const plugin = require('tailwindcss/plugin')
module.exports = {
plugins: [
plugin(function({ addVariant }) {
addVariant('loading', '&.loading') // here
})
],
};

Vue.js: How to change a class when a user has clicked on a link?

I am trying to add a class to an element depending on whether the user has clicked on a link. There is a similar question here but it is not working as I wanted it to be.
I created a component which has its own internal data object which has the property, isShownNavigation: false. So when a user clicks on the a I change isShownNavigation: true and expect my css class isClicked to be added. Alas that is not happening - isShownNavigation stays false in the component when I displayed it {{isShownNavigation}} but I can see in the console that my method is working when clicked.
I imported my header component to the App. Code is below.
Header Component
<template>
<header class="header">
<a
href="#"
v-bind:class="{isClicked: isShowNavigation}"
v-on:click="showNavigation">
Click
</a>
</header>
</template>
<script>
export default {
name: 'header-component',
methods: {
showNavigation: () => {
this.isShowNavigation = !this.isShowNavigation
}
},
data: () => {
return {
isShowNavigation: false
}
}
}
</script>
Application
<template>
<div id="app">
<header-component></header-component>
</div>
</template>
<script>
import HeaderComponent from './components/Header.vue'
export default {
name: 'app',
components: {
'header-component': HeaderComponent
}
}
</script>
I am using the pwa template from https://github.com/vuejs-templates/pwa.
Thanks.
Don't use fat arrow functions to define your methods, data, computed, etc. When you do, this will not be bound to the Vue. Try
export default {
name: 'header-component',
methods: {
showNavigation(){
this.isShowNavigation = !this.isShowNavigation
}
},
data(){
return {
isShowNavigation: false
}
}
}
See VueJS: why is “this” undefined? In this case, you could also really just get rid of the showNavigation method and set that value directly in your template if you wanted to.
<a
href="#"
v-bind:class="{isClicked: isShowNavigation}"
v-on:click="isShowNavigation = true">
Click
</a>
Finally, if/when you end up with more than one link in your header, you will want to have a clicked property associated with each link, or an active link property instead of one global clicked property.

Syncing a paper-input with firebase using polymer

How is this for a solution for syning the data from a paper input to a firebase database.
properties: {
teamid: {
type: String,
value: null
},
formid: {
type: String,
value: null
},
metaName: {
type: String,
value: null,
observer: '_updateMetaName'
}
},
_updateMetaName: function(metaName) {
var path = 'formModel/' + this.teamid + '/' + this.formid + '/meta/name';
firebase.database().ref(path).set(metaName);
},
The data metaName comes from a a paper-input element
<paper-input value="{{metaName}}"></paper-input>
I'm using an observer over the on-change attribute because I hate the idea that a user must move out of an input for it to persist.
I've also chosen not to use PolymerFire because i dosen't have some features I need and its not production ready.
I also don't like the idea that the observer runs multiple times before any data has been changed. And that should, i thought, break it but its working to my surprise.
What other options do I have?
Are their any disadvantages to my current solution?
One disadvantage is that every keystroke fires off a request to Firebase, which could be inefficient (a waste of CPU and bandwidth).
To address this, you could debounce the callback with this.debounce(jobName, callback, wait), as shown in the following demo.
HTMLImports.whenReady(_ => {
"use strict";
Polymer({
is: 'x-foo',
properties : {
metaName: {
type: String,
value: 'Hello world!',
observer: '_metaNameChanged'
}
},
_setFirebaseMetaName: function(metaName) {
var path = 'formModel/' + this.teamid + '/' + this.formid + '/meta/name';
//firebase.database().ref(path).set(metaName);
console.log('metaName', metaName);
},
_metaNameChanged: function(metaName) {
this.debounce('keyDebouncer',
_ => this._setFirebaseMetaName(metaName),
500);
}
});
});
<head>
<base href="https://polygit.org/polymer+1.5.0/components/">
<script src="webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="paper-input/paper-input.html">
</head>
<body>
<x-foo></x-foo>
<dom-module id="x-foo">
<template>
<paper-input label="Meta Name" value="{{metaName}}"></paper-input>
</template>
</dom-module>
</body>
codepen
I've decided to go with on-keyup="_updateViewDesc" to stop a error occurring when multiple clients have the same page open. Using observers, when some data updates, it triggers the observer on all the connected clients. Causing characters to go missing.

Hide Parent's sbling ui-view quadrant when in a child state

When I go to a child state, I want to hide a ui-view component of a quadrant ui-view in root state. How can achieve this.
##index.html
<div ui-view="a">
</div>
<div ui-view="b">
</div>
<div ui-view="c">
</div>
##b.html
<div ui-view>
</div>
##config
$stateProvider.state('start', {
'views': {
'a': {
templateUrl: ...
},
'b': {
templateUrl: 'b.html'
},
'c': {
templateUrl: ...
}
},
controller: 'indexController
}).state('start.all', {
templateUrl: 'd.html',
controller: 'allController'
});
So when I reach start.all, I would like that the ui-view tagged c vanishes. How can I accomplish this.
There is an example demonstrating approach discussed below. The native way of ui-router, I'd say, is to manage all the views from current (active) state. We can do it with :
View Names - Relative vs. Absolute Names
... Behind the scenes, every view gets assigned an absolute name that follows a scheme of viewname#statename, where viewname is the name used in the view directive and state name is the state's absolute name, e.g. contact.item
In our case, the full name of the view 'c' would be c#, i.e. c as view name, # as delimiter and empty string representing the root (a bit weird but in fact logical).
Having that we can change the start.all definition like this:
.state('start.all', {
url : '/all',
'views': {
'': {
template: '<span>this is start ALL</span>',
},
'c#': {
template: '<span></span>',
},
},
})
And we will change the content of the c view in the root. And that should be the most native way with ui-router. It does not effectively remove it, but we can replace it with some empty stuff.
Also, into your example above, I placed controller called bController as contra example to the indexController:
.state('start', {
url : '/start',
'views': {
'a': {
template: ...
},
'b': {
template: ...
// HERE a new controller bController
controller: 'bController',
},
'c': {
template: ...
}
},
// the orginal contoller
controller: 'indexController',
})
and also defined them this way:
.controller('indexController', function($scope, $state, $stateParams) {
console.log('indexConroller was invoked');
})
.controller('bController', function($scope, $state, $stateParams) {
console.log('bConroller was invoked');
})
Why? to show you, that indexController will never be invoked. Contollers belongs to templates/views not to state...
Check all that together here
You could do it in a few ways. One way would be to have an abstract state containing views a and b. That abstract state then has two concrete child states: start, which adds view c, and all, which adds view d.
Another option is to just use the ng-show directive on the c view's root element bound to some scope variable. I would go with the first option.
Notably this does not answer the question because all is no longer a child of start. If there is a real need for all to inherit from start (there appears to be no need at present) you can just make start abstract and create a start.main and start.all.
Though Radim's solution is very clever and much appreciated, I think this is much more readable and intuitive than overriding a parent view with an empty template.
<body>
<div ng-app="myApp">
<a ui-sref="start.main">start</a> | <a ui-sref="start.all">all</a>
<hr />
<div class="rootView" ui-view="a"></div>
<div class="rootView" ui-view="b"></div>
<div class="rootView" ui-view=""></div>
</div>
<script>
var myApp = angular.module('myApp', ['ui.router']);
myApp.config(function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/start/main');
$stateProvider
// Content common to all views
.state('shell', {
abstract: true,
views: {
"a": { template: '<div>View a here.</div>' },
"b": { template: '<div>View b here.</div>' },
"": { template: '<div ui-view></div>' }
}
})
// Content common to all 'start' views (currently nothing)
.state('start', {
parent: 'shell',
url: '/start',
abstract: true,
template: '<div ui-view></div>'
})
.state('start.main', {
url: '/main',
template: '<div>View c is here</div>'
})
.state('start.all', {
url: '/all',
template: '<div>View d is here</div>'
});
});
</script>
</body>

Resources