I created a dark and light mode in my laravel project and whenever the vue JS toggle is clicked it should create a cookie that saves the value. It works perfectly fine on google chrome but when i tried it on edge and firefox it showed (Undefined array key "isDarkModeOn").
I just want this cookie to be saved to any browser
My toggle Vue component which includes create cookie
<template>
<div
class="flex cursor-pointer items-center justify-between"
#click="store.modeToggle(), modeToggle()"
>
<div
class="flex h-4 w-12 items-center rounded-full bg-gray-300 p-1 duration-300 ease-in-out"
:class="{ 'bg-green-400': store.toggleActive }"
>
<div
class="h-3 w-3 transform rounded-full bg-white shadow-md duration-300 ease-in-out"
:class="{ 'translate-x-7': store.toggleActive }"
></div>
</div>
</div>
</template>
<script>
import { store } from "./store.js";
export default {
props: ["theme"],
data() {
return {
store,
};
},
mounted() {
if (this.theme === "false") {
store.light();
} else {
store.dark();
}
},
methods: {
dark() {
this.$emit("dark");
},
light() {
this.$emit("light");
},
modeToggle() {
if (
this.darkMode ||
document.querySelector("body").classList.contains("dark")
) {
this.light();
} else {
this.dark();
}
const isDarkModeOn = store.toggleActive;
createCookie("isDarkModeOn", isDarkModeOn.toString(), 60 * 60 * 24);
},
},
};
</script>
<style></style>
my Js file which contains the logic for creating the cookie
function createCookie(name, value, timeInSeconds) {
var date = new Date();
date.setTime(date.getTime() + timeInSeconds * 1000);
var expires = "; expires=" + date.toGMTString();
document.cookie = name + "=" + value + expires + "; path=/";
}
function getCookie(cname) {
let name = cname + "=";
let decodedCookie = decodeURIComponent(document.cookie);
let ca = decodedCookie.split(";");
for (let i = 0; i < ca.length; i++) {
let c = ca[i];
while (c.charAt(0) == " ") {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
window.onload = function () {
const isDarkModeOn = getCookie("isDarkModeOn");
if (isDarkModeOn === "true") document.body.classList.add("dark");
};
and this is how I tell browser to display dark class or hide it according to the cookie if it exists
<body id="app" style="font-family: Open Sans, sans-serif" class="scroll-smooth {{ $_COOKIE[('isDarkModeOn')] === 'true' ? 'dark' : '' }}">
It works on chrome but not on any other browser.
Also when testing in Laravel like this
#if ($value = $_COOKIE['isDarkModeOn'])
{{ $value }}
#else
'not found'
#endif
It echos the value not problem so since there is a cookie why any other browser can't identify it
As for your test, you should use something more safe (doesnt trigger an error when absent)
#if (isset($_COOKIE['isDarkModeOn']))
{{ $_COOKIE['isDarkModeOn'] }}
#else
'not found'
#endif
Issue is solved by adding the below lines of code before the body
<?php
if (isset($_COOKIE['isDarkModeOn'])) {
$cookie = $_COOKIE['isDarkModeOn'];
} else {
$cookie = '';
}
?>
Not the best way to do it but It did the trick
Related
I recently ran into an issue when building a Laravel Livewire component where the javascript portion wouldn't update when a select input changed. The component is a chart from the Chartist.js library and it displays on load but when I change the select input the chart disappears. I came up with a solution but it feels dirty, anyone have a better solution to this.
line-chart.blade.php
<div class="mt-6">
<h2 class="text-xl text-gray-600 py-3 font-bold">Location Views</h2>
<div class="bg-white rounded-lg shadow overflow-hidden overflow-y-scroll">
<div class="flex justify-end px-10 py-6">
<select wire:model="days" class="block w-40 pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-yellow-500 focus:border-yellow-500 sm:text-sm rounded-md">
<option value="30">Last 30 Days</option>
<option value="365">Last 12 Months</option>
</select>
</div>
<div id="line-chart" class="relative ct-chart">
<div class="hidden absolute inline-block chartist-tooltip bg-white text-xs shadow text-center px-3 py-1 rounded-md w-36">
<span class="chartist-tooltip-key"></span><br>
<span class="chartist-tooltip-date"></span><br>
<span class="chartist-tooltip-value"></span>
</div>
</div>
</div>
</div>
#push('styles')
<link rel="stylesheet" href="//cdn.jsdelivr.net/chartist.js/latest/chartist.min.css">
#endpush
#push('scripts')
<script src="//cdn.jsdelivr.net/chartist.js/latest/chartist.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartist-plugin-tooltips#0.0.17/dist/chartist-plugin-tooltip.min.js"></script>
#endpush
#push('js')
<script>
document.addEventListener('livewire:load', function () {
setTimeout(() => {
Livewire.emit('updateJS')
})
Livewire.on('updateJS', function () {
var data = {
labels: #this.labels,
// Our series array that contains series objects or in this case series data arrays
series: #this.data,
};
var options = {
height: 300,
fullWidth: true,
chartPadding: 40,
axisX: {
offset: 12,
showGrid: true,
showLabel: true,
},
axisY: {
offset: 0,
showGrid: true,
showLabel: true,
onlyInteger: true,
},
}
new Chartist.Line('#line-chart', data, options).on("draw", function (data) {
if (data.type === "point") {
data.element._node.addEventListener('mouseover', e => {
const tooltip = document.getElementsByClassName('chartist-tooltip')
tooltip[0].style.top = data.y - 75 + 'px'
tooltip[0].style.left = data.x > 200 ? data.x - 150 + 'px' : data.x + 'px'
tooltip[0].classList.remove('hidden')
const key = document.getElementsByClassName('chartist-tooltip-key')
key[0].innerHTML = data.meta[1]
const meta = document.getElementsByClassName('chartist-tooltip-date')
meta[0].innerHTML = data.meta[0]
const value = document.getElementsByClassName('chartist-tooltip-value')
value[0].innerHTML = data.value.y === 1 ? data.value.y + ' view' : data.value.y + ' views'
})
data.element._node.addEventListener('mouseleave', e => {
const tooltip = document.getElementsByClassName('chartist-tooltip')
tooltip[0].classList.add('hidden')
})
}
})
})
})
</script>
#endpush
LineChart.php
<?php
namespace App\Http\Livewire\Components;
use Carbon\Carbon;
use Carbon\CarbonPeriod;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\View\Factory;
use Illuminate\Contracts\View\View;
use Illuminate\Support\Collection;
use Livewire\Component;
class LineChart extends Component
{
/**
* #var Collection
*/
public Collection $data;
/**
* #var array
*/
public array $labels;
/**
* #var int
*/
public int $days = 30;
/**
*
*/
public function mount()
{
$this->data();
$this->labels = $this->labels();
}
/**
* Trigger mount when days is updated.
*/
public function updatedDays()
{
$this->mount();
$this->emit('updateJS');
}
/**
* #return Application|Factory|View
*/
public function render()
{
return view('livewire.components.line-chart');
}
/**
* Generates the chart data.
*/
public function data()
{
$locations = request()->user()->locations;
if ($this->days === 30) {
$this->data = $locations->map(function ($location) {
return $this->getDatesForPeriod()->map(function ($date) use ($location) {
return [
'meta' => [
Carbon::parse($date)->format('M j'),
$location->name
],
'value' => $location->views->filter(function ($view) use ($date) {
return $view->viewed_on->toDateString() === $date;
})->count()
];
})->toArray();
});
}
if ($this->days === 365) {
$this->data = $locations->map(function ($location) {
return $this->getDatesForPeriod()->map(function ($date) use ($location) {
return [
'meta' => [
Carbon::parse($date)->format('M'),
$location->name
],
'value' => $location->views->filter(function ($view) use ($date) {
return $view->viewed_on->month === Carbon::parse($date)->month;
})->count()
];
})->toArray();
});
}
}
/**
* Creates the labels for the chart.
*
* #return array
*/
protected function labels()
{
return $this->getDatesForPeriod()->map(function ($date) {
if ($this->days === 30) {
return Carbon::parse($date)->format('M j');
} else {
return Carbon::parse($date)->format('M');
}
})->toArray();
}
/**
* Gets the dates for the specified period.
*
* #return Collection
*/
protected function getDatesForPeriod()
{
if ($this->days === 30) {
return collect(CarbonPeriod::create(now()->subDays($this->days)->toDateString(), now()->toDateString()))
->map(function ($date) {
return $date->toDateString();
});
}
if ($this->days === 365) {
return collect(now()->startOfMonth()->subMonths(11)->monthsUntil(now()))
->map(function ($date) {
return $date->toDateString();
});
}
}
}
If I change document.addEventListener('livewire:load', function () {} to livewire:update then the chart works as expected when I use the select input, but then the chart doesn't display on load. So to get around this I had to set a timeout and trigger an event that displays the chart on load but will also display the chart on update. I feel like there is a better way to do this, I'm just missing something.
To get this to work I removed the setTimeout() and the Livewire.On('updateJS') and added another event listener inside of livewire:load that listens for livewire:update and in here we're updating the chart with
chart.update({labels: #this.labels, series: #this.data})
Here is the entire code snippet. I feel like this is a much cleaner solution and doesn't feel dirty lol.
<script>
document.addEventListener('livewire:load', function () {
var data = {
labels: #this.labels,
// Our series array that contains series objects or in this case series data arrays
series: #this.data,
};
var options = {
height: 300,
fullWidth: true,
chartPadding: 40,
axisX: {
offset: 12,
showGrid: true,
showLabel: true,
},
axisY: {
offset: 0,
showGrid: true,
showLabel: true,
onlyInteger: true,
},
}
const chart = new Chartist.Line('#line-chart', data, options).on("draw", function (data) {
if (data.type === "point") {
data.element._node.addEventListener('mouseover', e => {
const tooltip = document.getElementsByClassName('chartist-tooltip')
tooltip[0].style.top = data.y - 75 + 'px'
tooltip[0].style.left = data.x > 200 ? data.x - 150 + 'px' : data.x + 'px'
tooltip[0].classList.remove('hidden')
const key = document.getElementsByClassName('chartist-tooltip-key')
key[0].innerHTML = data.meta[1]
const meta = document.getElementsByClassName('chartist-tooltip-date')
meta[0].innerHTML = data.meta[0]
const value = document.getElementsByClassName('chartist-tooltip-value')
value[0].innerHTML = data.value.y === 1 ? data.value.y + ' view' : data.value.y + ' views'
})
data.element._node.addEventListener('mouseleave', e => {
const tooltip = document.getElementsByClassName('chartist-tooltip')
tooltip[0].classList.add('hidden')
})
}
})
document.addEventListener('livewire:update', function () {
chart.update({labels: #this.labels, series: #this.data})
})
})
</script>
I never used the chartist, but I usually use this approach (let me know if the code make sense to you).
<div class="mt-6" x-data="{
labels: #entangle('labels'),
series: #entangle('data'),
chart: null
}"
x-init="() => {
const options = {}; // I'll omit part of the code here
chart = new Chartist.Line('#line-chart', data, options);
},
$watch('series', (dataChart) => {
// I usually put both, the series data and the labels in an associative array on the livewire component back-end
const { series, labels } = dataChart;
chart.update(dataChart);
"
>
<h2 class="text-xl text-gray-600 py-3 font-bold">Location Views</h2>
<div class="bg-white rounded-lg shadow overflow-hidden overflow-y-scroll">
<div class="flex justify-end px-10 py-6">
<select wire:model="days" class="block w-40 pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-yellow-500 focus:border-yellow-500 sm:text-sm rounded-md">
<option value="30">Last 30 Days</option>
<option value="365">Last 12 Months</option>
</select>
</div>
<div id="line-chart" class="relative ct-chart">
<div class="hidden absolute inline-block chartist-tooltip bg-white text-xs shadow text-center px-3 py-1 rounded-md w-36">
<span class="chartist-tooltip-key"></span><br>
<span class="chartist-tooltip-date"></span><br>
<span class="chartist-tooltip-value"></span>
</div>
</div>
</div>
</div>
I think that watching a value from the livewire component it's easier to debug. The use of events to make the communication between back and front-end can make debug challenge when the page gets bigger (and with a lot of events).
With this code your char will be loaded after livewire initial load (you don't need to check the 'livewire:load' event). The chart instance will not be mounted every time you dispatch the updateJS event, only the data will be update.
Ps: I don't know how Chartist works, so I didn't put the code on chart.update(...), but since it's a chart lib it should have an options to update the data. I just want to show you my approach, hope it helps.
I develop an ecommerce application in nuxtjs frontend and laravel backend.But it is difficult to upload image and save it in the database.Can anyone help me solve the problem ?
Here example of Nuxt Or Vuejs image uploader with Laravel API. I left a comment inside the code for you.
First of all, you must make upload.vue component with this content.
<template>
<div class="container">
<label class="custom-file" for="file">
{{files.length ? `(${files.length}) files are selected` : "Choose files"}}
<input #change="handleSelectedFiles" id="file" multiple name="file" ref="fileInput" type="file">
</label>
<!--Show Selected Files-->
<div class="large-12 medium-12 small-12 cell">
<div class="file-listing" v-for="(file, key) in files">{{ file.name }} <span class="remove-file" v-on:click="removeFile( key )">Remove</span></div>
</div>
<!--Submit Button && Progress Bar-->
<div>
<button #click="upload">Start Upload</button>
- Upload progress : {{this.progress}}
</div>
</div>
</template>
<script>
export default {
data() {
return {
files : [],
progress: 0
}
},
computed: {
/*The FormData : Here We Make A Form With Images Data To Submit.*/
form() {
let form = new FormData();
this.files.forEach((file, index) => {
form.append('files[' + index + ']', file);
});
return form;
}
},
methods : {
handleSelectedFiles() {
let selectedFiles = this.$refs.fileInput.files;
for (let i = 0; i < selectedFiles.length; i++) {
/*Check Already Has Been Selected Or Not ...*/
let isFileExists = this.files.find(file => file.type === selectedFiles[i].type && file.name === selectedFiles[i].name && file.size === selectedFiles[i].size && file.lastModified === selectedFiles[i].lastModified);
if (!isFileExists)
this.files.push(selectedFiles[i]);
}
},
removeFile(key) {
this.files.splice(key, 1);
},
upload() {
const config = {
onUploadProgress: (progressEvent) => this.progress = Math.round((progressEvent.loaded * 100) / progressEvent.total)
};
this.$axios.post('host-url/upload-image', this.form, config)
.then(res => {
this.progress = 0;
this.files = [];
console.log(res)
})
.catch(err => console.log(err))
}
}
}
</script>
<style>
.custom-file {
padding: 1.2rem;
border-radius: .8rem;
display: inline-block;
border: 2px dashed #a0a0a0;
}
.custom-file input {
display: none;
}
</style>
After this, we must make an endpoint in Laravel API routes like this:
Route::post('/upload-image', 'UploadController#image');
In the last, Put this codes on upload
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class UploadController extends Controller
{
public function image(Request $request)
{
$request->validate([
'files' => ['required', 'array'],
'files.*' => ['required', 'image','min:5','max:5000']
]);
$uploadedFiles = [];
foreach ($request->file('files') as $file) {
$fileName = bcrypt(microtime()) . "." . $file->getClientOriginalExtension();
$file->move('/uploads', $fileName);
array_push($uploadedFiles, "/uploads/{$fileName}");
}
return response($uploadedFiles);
}
}
Attention: Progress in localhost is so fast, then if you want to test it in local upload a file largest than 50 MB.
I have passed this collection (postFavourite) to my vue component via props.
[{"id":1,"user_id":1,"post_id":2,"created_at":"2018-07-24 09:11:52","updated_at":"2018-07-24 09:11:52"}]
How do I then check if any instance of user_id in the collection is equal to userId which is the current logged in user (also sent via props).
Tried
let pf = _.find(this.postFavourite, { "user_id": this.userId})
Keep getting undefined as the value of the pf variable even though this.userID is equal to 1.
New to JS and Vue.js so any help would be great.
Here is the vue component code.
<template>
<div>
<i v-show="this.toggle" #click="onClick" style="color: red" class="fas fa-heart"></i>
<i v-show="!(this.toggle)" #click="onClick" style="color: white" class="fas fa-heart"></i>
</div>
</template>
<script>
export default {
data() {
return {
toggle: 0,
}
},
props: ['postData', 'postFavourite', 'userId'],
mounted() {
console.log("Post is :"+ this.postData)
console.log("User id is: "+ this.userId)
console.log("Favourite Object is :" +this.postFavourite);
console.log(this.postFavourite.find(pf => pf.user_id == this.userId));
},
methods: {
onClick() {
console.log(this.postData);
this.toggle = this.toggle ? 0 : 1;
}
}
}
</script>
This is how I passed the props to vue
<div id="app">
<favorite :post-data="'{{ $post->id }}'" :post-favourite="'{{Auth::user()->favourite }}'" :user-id="'{{ $post->user->id }}'"></favorite>
</div>
I gave up on lodash and find and just messed around with the data in the chrome console to work out how to check the value I wanted.
Then I built a loop to check for the value.
If it found it toggle the like heart on of not leave it off.
This will not be the best way to solve this problem but I'm just pleased I got my first real vue component working.
<template>
<div>
<i v-show="this.toggle" #click="onClick" style="color: red" class="fas fa-heart"></i>
<i v-show="!(this.toggle)" #click="onClick" style="color: white" class="fas fa-heart"></i>
</div>
</template>
<script>
export default {
props: ['postData', 'postFavourite', 'userId']
,
data() {
return {
toggle: 0,
favs: [],
id: 0
}
},
mounted () {
var x
for(x=0; x < this.postFavourite.length; x++){
this.favs = this.postFavourite[x];
if(this.favs['post_id'] == this.postData) {
this.toggle = 1
this.id = this.favs['id']
}
}
},
methods: {
onClick() {
console.log(this.postData)
if(this.toggle == 1){
axios.post('favourite/delete', {
postid: this.id
})
.then(response => {})
.catch(e => {
this.errors.push(e)
})
}
else if(this.toggle == 0){
axios.post('favourite', {
user: this.userId,
post: this.postData
})
.then(response => {
this.id = response.data
})
.catch(e => {
this.errors.push(e)
})
}
this.toggle = this.toggle ? 0 : 1;
}
}
}
</script>
Where I pass my props.
<favorite :post-data="'{{ $post->id }}'"
:post-favourite="{{ Auth::user()->favourite }}"
:user-id="'{{ Auth::user()->id }}'"></favorite>
Thanks to all that tried to help me.
From just the code you provided, I see no issue. However lodash is not required for this problem.
Using ES2015 arrow functions
let pf = this.postFavourite.find(item => item.user_id === this.userId);
Will find the correct item in your array
You can read more about this function in the mdn webdocs
You can use find() directly on this.postFavourite like this:
this.postFavourite.find(pf => pf.user_id == this.userId);
Here is another way to do it that might help you as well.
[EDIT]
In order to use find() the variable needs to be an array, this.postFavourite is sent as a string if you didn't use v-bind to pass the prop thats what caused the error.
To pass an array or an object to the component you have to use v-bind to tell Vue that it is a JavaScript expression rather than a string. More informations in the documentation
<custom-component v-bind:post-favourite="[...array]"></custom-component>
Hello I am building one project. Where user can send up to 5 images and up to 10 songs with the text. But when I send request to the server, where I handle with Laravel, I can't get those files.
// my data object from VueJS
data() {
return {
formData: new FormData(),
pikir: {
body: '',
},
isLoading: false,
images: [],
songs: [],
}
}
// imagePreview method from VuejS
imagePreview(event) {
let input = event.target;
if (input.files[0]) {
if (input.files.length <= 5) {
for (let i = 0; i < input.files.length; i++) {
let reader = new FileReader();
reader.onload = e => {
this.images.push(e.target.result);
}
reader.readAsDataURL(input.files[i]);
}
Array.from(Array(event.target.files.length).keys())
.map(x => {
this.formData
.append('images',
event.target.files[x], event.target.files[x].name);
});
} else {
alert('You can upload up to 5 images');
}
}
}
// musicPreview method from VueJS
musicPreview(event) {
let input = event.target;
if (input.files.length <= 5) {
for (let i = 0; i < input.files.length; i++) {
this.songs.push(input.files[i].name.replace('.mp3', ''));
}
Array.from(Array(event.target.files.length).keys())
.map(x => {
this.formData
.append('songs',
event.target.files[x], event.target.files[x].name);
});
} else {
alert('You can upload up to 10 songs');
}
}
// sharePikir method from VueJS
sharePikir() {
this.formData.append('body', this.pikir.body);
axios.put('/api/pikirler', this.formData)
.then(response => {
this.pikir.body = '';
this.isLoading = false;
})
.catch(() => {
this.isLoading = false;
});
},
<form action="#" id="share-pikir">
<label for="pikir">
Näme paýlaşmak isleýärsiňiz? {{ pikirSymbolLimit }}
</label>
<input type="text" name="pikir" id="pikir" maxlength="255"
v-model="pikir.body"
#keyup="handleSymbolLimit()">
<div class="emoji">
<i class="fa fa-smile-o"></i>
</div>
<div class="photo-music left">
<label for="music-upload">
<i class="fa fa-music"></i>
</label>
<input type="file" name="songs[]" id="music-upload"
accept="audio/mp3"
#change="musicPreview($event)"
multiple>
<i class="divider"></i>
<label for="image-upload">
<i class="fa fa-image"></i>
</label>
<input type="file" name="images[]" id="image-upload"
#change="imagePreview($event)"
multiple>
</div>
<div class="share right">
<button
:class="{ 'btn-medium': true, 'is-loading': isLoading }"
#click.prevent="sharePikir($event)">
Paýlaşmak
</button>
</div>
</form>
I put my front end stuff above and in my Laravel side I just return all requests:
public function store(){
return request()->all();
}
And these are what I get from request:
I couldn't found what is wrong. Thank you in advance.
Oh yeah! you're missing this part. You need to define this.
axios.defaults.headers.post['Content-Type'] = 'multipart/form-data';
this my solutuion
export default {
data (){
return {
attachment : { name : null,file: null }
}
},
methods : {
onFileChange(event) {
this.attachment.file = event.target.files[0]
},
attachmentCreate() {
var form = new FormData();
form.append('name',this.attachment.name);
form.append('file',this.attachment.file);
this.$http.post('attachment',form).then(response=>{
console.log("oke")
})
},
}
}
<input type="file" class="form-control" #change="onFileChange">
Check this post, maybe your problem is solved:
[https://stackoverflow.com/questions/55895941/success-upload-file-via-postman-but-fail-on-front-end-vue/73698108#73698108][1]
Working on a ember app. I have this form that takes in name, cc number, expiration and security number. I am able to backspace on name however I cant delete any of the other content, and this only happens in Firefox.
<div class="form-group cc-name input-row {{if nameValid 'has-success'}}">
<label class="label label--sm">Name on Card</label>
{{input type="text" value=name class="form-control"}}
</div>
<div class="form-group cc-number input-row {{if numberValid 'has-success'}}">
<label for="cc-number" class="label label--sm">Credit Card Number</label>
{{input-credit-card-number number=number class="form-control"}}
<div class="card-type {{if type 'show' 'hide'}}">
{{#if type}}
{{inline-svg type class="icon icon--credit-card"}}
{{/if}}
</div>
</div>
<div class="input-row input-row--inline">
<div class="form-group cc-expiration input-col--50 {{if expirationValid 'has-success'}}">
<label class="control-label label--sm">Expiration</label>
{{input-credit-card-expiration month=month year=year class="form-control"}}
</div>
<div class="form-group cc-cvc input-col--50 {{if cvcValid 'has-success'}}">
<label class="control-label label--sm">Security Code</label>
{{input-credit-card-cvc cvc=cvc class="form-control"}}
</div>
</div>
This is the code I need to override:
import Ember from 'ember';
import hasTextSelected from 'ember-credit-cards/utils/has-text-selected';
import formatters from 'ember-credit-cards/utils/formatters';
import cards from 'ember-credit-cards/utils/cards';
var cardFromNumber = cards.fromNumber;
var computed = Ember.computed;
function inputValid(value) {
value = (value + '').replace(/\D/g, '');
var card = cardFromNumber(value);
if (card) {
return value.length <= card.length[card.length.length - 1];
} else {
return value.length <= 16;
}
}
export default Ember.TextField.extend({
classNames: ['input-credit-card-number'],
placeholder: '•••• •••• •••• ••••',
autocomplete: 'cc-number',
type: 'tel',
keyPress: function(e) {
var digit = String.fromCharCode(e.which);
console.log(digit);
if (!/^\d+$/.test(digit)) {
return false;
}
var el = this.$();
if (hasTextSelected(el)) {
return true;
}
var value = el.val() + digit;
return inputValid(value);
console.log(value);
},
value: computed('number', function(key, value) {
var number = this.get('number');
if (arguments.length > 1) {
number = value;
this.set('number', value);
}
return formatters.formatNumber(number);
})
});
This code works for me:
export default Ember.TextField.extend({
classNames: ['input-credit-card-number'],
placeholder: '•••• •••• •••• ••••',
autocomplete: 'cc-number',
type: 'tel',
keyPress: function(e) {
if (e.keyCode == 46 || e.keyCode == 8 || e.keyCode == 9 || e.keyCode == 27 || e.keyCode == 13){
return true;
}
var digit = String.fromCharCode(e.which);
if (!/^\d+$/.test(digit)) {
return false;
}
var el = this.$();
if (hasTextSelected(el)) {
return true;
}
var value = el.val() + digit;
return inputValid(value);
console.log(value);
},
value: computed('number', function(key, value) {
var number = this.get('number');
if (arguments.length > 1) {
number = value;
this.set('number', value);
}
return formatters.formatNumber(number);
})
});