I have 2 of the same components in my laravel blade view, but they are conflicting.
What i'm trying to accomplish:
I've made a vue component that uploads a file to firebase and stores it in my database. In my blade view i have 2 places where i want to use this component. I configure the component with props so the component knows where to store the file.
What going wrong:
Every time i try to upload a file with the second component, i fire the function in the first component. How do i fix that the components can't conflict?
My laravel balde view:
component 1
<uploadfile
:key="comp100"
:user_data="{{ Auth::user()->toJson() }}"
store_path="/users/{{ Auth::user()->username }}/settings/email_backgrounds"
:store_route="'settings.project_email'"
:size="1000"
fillmode="cover"
></uploadfile>
component 2
<uploadfile
:key="comp200"
:user_data="{{ Auth::user()->toJson() }}"
store_path="/users/{{ Auth::user()->username }}/settings/email_backgrounds"
:store_route="'settings.project_email'"
:size="1000"
fillmode="cover"
></uploadfile>
The Vue component:
<template>
<div class="vue-wrapper">
<FlashMessage position="right top"></FlashMessage>
<div v-if="loading" class="lds-dual-ring"></div>
<div class="field">
<div class="control">
<label class="button main-button action-button m-t-20" for="uploadFiles"><span style="background-image: url('/images/icons/upload.svg')"></span>Kies bestand</label>
<input type="file" name="uploadFiles" id="uploadFiles" class="dropinput" #change="selectFile">
</div>
</div>
</div>
</template>
<script>
import { fb } from '../../firebase.js';
export default {
data() {
return {
fileObject: {
filePath: null,
url: null,
file: null,
resizedPath: null
},
loading: false
};
},
mounted() {
console.log(this.size)
console.log(this.fillmode)
},
props: [
'user_data',
'store_path',
'store_route',
'size',
'fillmode'
],
methods: {
selectFile(event)
{
var file = event.target.files[0];
this.fileObject.file = file
this.fileObject.filePath = this.store_path + '/' + file.name
this.fileObject.resizedPath = this.store_path + '/resized-' + file.name
if(file.type == 'image/png' || file.type == 'image/jpeg')
{
this.uploadFile(this.fileObject)
} else {
this.flashMessage.success({
title: 'Oeps!',
message: 'De afbeelding moet een png of een jpeg zijn!',
blockClass: 'success-message'
});
}
},
uploadFile(fileObject)
{
var vm = this
console.log(fileObject)
var storageRef = fb.storage().ref(fileObject.filePath)
var uploadTask = storageRef.put(fileObject.file)
this.loading = true
uploadTask.on('state_changed', function(snapshot){
var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
},function(error) {
}, function() {
var resizeImage = fb.functions().httpsCallable('resizeImage')
resizeImage({filePath: fileObject.filePath, contentType: fileObject.file.type, watermark: false, size: vm.size, fit: vm.fillmode}).then(function(result){
var downloadRef = fb.storage().ref(fileObject.resizedPath);
downloadRef.getDownloadURL().then(function(url){
fileObject.url = url
vm.loading = false
vm.storeImage(fileObject)
}).catch(function(error){
console.log(error)
})
}).catch(function(error){
});
});
},
storeImage(file)
{
axios.post('/api/app/store_file', {
api_token: this.user_data.api_token,
user: this.user_data,
file: file,
storeRoute: this.store_route
}).then((res) => {
location.reload()
}).catch((e) => {
});
}
}
}
</script>
Does someone know how to fix this?
I am using FullCalendar 3.1.0 plugin to show events. I was able to implement multiple events with a dropdown. But user is only able to select 1 option from a single dropdown filter. My goal is to give the opportunity to select multiple options in a each dropdown filter. I am using dropdown. But when I hold down CTR and click on options, it only shows events for the first option in the list. Any help would be greatly appreciated.
Here is the HTML:
<!-- Main view: Title and calendar -->
<div class="container">
<div class="row">
<div class="col-xs-12">
<h1 id="cal_title">Change Calendar</h1>
<div class="search_bar">
<ul id="menu">
Search By:
<li>
<select id="status_selector" multiple>
<option value="all" selected="selected">Status Types - All</option>
</select>
</li>
<li>
<select id="group_selector" multiple>
<option value="all" selected="selected">Group - All</option>
</select>
</li>
<li>
<select id="changeType_selector" multiple>
<option value="all" selected="selected">Type of Change - All</option>
<option value="6250">Emergency Change</option>
<option value="6882">Expedited Change</option>
<option value="6249">Normal Change</option>
<option value="9999">Standard Change</option>
</select>
</li>
<li>
<select id="downtime_selector" multiple>
<option value="all" selected="selected">Downtime - All</option>
<option value="Yes">Yes</option>
<option value="No">No</option>
</select>
</li>
</ul>
</div>
<div id="calendar"></div>
<div id="footer">To ensure optimal performance, only changes created in the past 90 days are shown. For changes older than 90 days please reference EasyVista. <br />If an issue has been found and/or you have a recommendation, please open a ticket for Service Request/Applications/EasyVista - Other Request, explaining the issue or recommendation.</div>
<div id="version">SACC v2.0</div>
</div>
</div>
</div>
Here is my Javascript:
$(document).ready(function() {
/* Find all the distinct STATUS_EN and place them into a dropdown list */
// This creates first 2 dropdown dynamically
$.getJSON('json/events.json',function(json){
var usedStatus = []; // Array to keep track of all STATUS_EN that have been seen
var usedGroup = []; // Array to keep track of all group_selector that have been seen
// For each object, store the status/group in predefined variables
$.each(json, function(i,v){
// If STATUS_EN has not been seen
if (usedStatus.indexOf(v.STATUS_EN) == -1){
usedStatus.push(v.STATUS_EN); // Add STATUS_EN to usedStatus
}
// If responsible_group has not been seen
if (usedGroup.indexOf(v.responsible_group) == -1){
usedGroup.push(v.responsible_group); // Add responsible_group to usedStatus
}
});
// Sort both array variables in alphabetical order.
usedStatus.sort();
usedGroup.sort();
// Create the dropdown
usedStatus.forEach(function(value){
if (value != undefined){ // If STATUS_EN is not undefined
$("#status_selector").append('<option value="'+value+'">'+value+'</option>'); // Create an option for the dropdown list
}
});
usedGroup.forEach(function(value){
if (value != undefined){ // If responsible_group is not undefined
$("#group_selector").append('<option value="'+value+'">'+value+'</option>'); // Create an option for the dropdown list
}
});
});
/* If end_date is null, return start_date */
function isNull(end_date,start_date){
if(end_date !== null){
return end_date;
} else {
return start_date;
}
}
/* Calendar structure */
$('#calendar').fullCalendar({
/* Theme enabler */
theme: false,
/* Header description */
header: {
left: 'prev,today,next',
center: 'title',
right: 'month,basicWeek,basicDay'
},
/* Set the default view to Day */
defaultView: 'basicWeek',
/* Arrow stype (Used when theme is enabled) */
themeButtonIcons: {
prev: 'circle-triangle-w',
next: 'circle-triangle-e'
},
/* Text to show in the button */
buttonText: {
today: 'Today',
month: 'Month',
week: 'Week',
day: 'Day',
list: 'Week List'
},
navLinks: true, // Can click day/week names to navigate views
editable: false, // Remove permission to move events
eventLimit: true, // Allow "more" link when too many events
businessHours: true, // grayout afterhours
multiple: true,
/* Function that allows user to click on event. */
eventClick: function (event, jsEvent, view) {
//set the values and open the modal
$('#modalTitle').html(event.title);
$('#modalBody').html(event.text);
$('#eventUrl').attr('href', event.url);
$('#eventStatus').html("Status: " + event.STATUS_EN);
$('#fullCalModal').modal('show');
return false; // prevent from going to EasyVista right away
},
/* Function that shows description when hovering over event */
eventMouseover: function (data, event, view) {
tooltip = '<div class="tooltiptopicevent">'
+ '<strong>Request Number:</strong> ' + data.RFC_NUMBER
+ '<br /><strong>Status:</strong> ' + data.STATUS_EN
+ '<br /><strong>Start Date:</strong> ' + moment(data.start).format("MM/D, h:mm:ss a")
+ '<br /><strong>End Date:</strong> ' + moment(isNull(data.end,data.start)).format("MM/D, h:mm:ss a")
+ '<br /><strong>Description:</strong> ' + data.text + '</div>';
$("body").append(tooltip);
$(this).mousemove(function(event){
$(".tooltiptopicevent").position({
my: "left+3 bottom-3",
of: event,
collision: "flipfit"
});
});
},
/* Hide description when mouse moves out */
eventMouseout: function (data, event, view) {
$(this).css('z-index', 8);
$('.tooltiptopicevent').remove();
},
/* Feed in events from JSON file through PHP */
events: {
url: 'php/get-events.php'
},
/* Render the events */
eventRender: function eventRender(event, element, view){
return['all',event.STATUS_EN].indexOf($('#status_selector option:selected').val()) >= 0
&& ['all',event.responsible_group].indexOf($('#group_selector option:selected').val()) >= 0
&& ['all',event.change_type].indexOf($('#changeType_selector option:selected').val()) >= 0
&& ['all',event.downtime].indexOf($('#downtime_selector option:selected').val()) >= 0
},
/* Show status loading when loading */
loading: function(bool) {
$('#loading').toggle(bool);
}
});
/* Call on fullCalendar after selection of dropdown option
$('#status_selector, #group_selector, #changeType_selector, #downtime_selector').change(function() {
$('#calendar').fullCalendar('rerenderEvents');
//$('#calendar').fullCalendar('refetchEvents'); // this allows the spinner to come up each time filter is changed.
});*/
/**/
$('#status_selector, #group_selector, #changeType_selector, #downtime_selector').on('change',function(){
$('#calendar').fullCalendar('rerenderEvents');
});
});
Sample of how my .json file looks like:
[
{
"start": "2016-12-2T17:0:00",
"end": "2016-12-2T17:0:00",
"title": "12/2/2016 5:00 PM - group1",
"url": "https://sample.com",
"text": "some needed text",
"description": "description of event",
"REQUEST_ID": 462820,
"STATUS_EN": "Open",
"downtime": "No",
"change_type": "9999",
"responsible_group": "group1",
"RFC_NUMBER": "C201612_09454"
},
{
"start": "2017-2-1T21:0:00",
"end": "2017-2-1T21:0:00",
"title": "2/1/2017 9:00 PM - group2",
"url": "https://samplesite.com",
"text": "some text",
"description": "description of event",
"REQUEST_ID": 521157,
"STATUS_EN": "Closed",
"downtime": "No",
"change_type": "6250",
"responsible_group": "group2",
"RFC_NUMBER": "C201702_00976"
}
]
Doing .val() on a group of selected elements (e.g. your $('#status_selector option:selected').val()) will only return the value from the first matched element - as per the very first line of the docs: http://api.jquery.com/val/
So you need to loop through and check the values of all the selected options, and test for them individually. Something like this (untested):
eventRender: function eventRender(event, element, view){
var statusMatch = false;
var statusArr = ['all',event.STATUS_EN];
$('#status_selector option:selected').each(function(index, el)
{
if (statusArr.indexOf($(this).val()) > = 0) statusMatch = true;
});
var groupMatch = false;
var groupArr = ['all',event.responsible_group];
$('#group_selector option:selected').each(function(index, el)
{
if (groupArr.indexOf($(this).val()) > = 0) groupMatch = true;
});
var changeMatch = false;
var changeArr = ['all',event.change_type];
$('#changeType_selector option:selected').each(function(index, el)
{
if (changeArr.indexOf($(this).val()) > = 0) changeMatch = true;
});
var downtimeMatch = false;
var downtimeArr = ['all',event.downtime];
$('#downtime_selector option:selected').each(function(index, el)
{
if (downtimeArr.indexOf($(this).val()) > = 0) downtimeMatch = true;
});
return (statusMatch && groupMatch && changeMatch && downtimeMatch);
}
I am developing an application with with Laravel 5.3 and Vue 2 I implemented a form-validation via Vue 2 but the it doesn't check the request for any errors on client-side it firstly lets every single request to be sent to the server and then displays the errors which are sent back from the server, in the following you can find my code
class Form {
constructor(data) {
this.originalData = data;
for (let field in data) {
this[field] = data[field];
}
this.errors = new Errors();
}
data() {
let data = {};
for (let property in this.originalData) {
data[property] = this[property];
}
return data;
}
reset() {
for (let field in this.originalData) {
this[field] = '';
}
this.errors.clear();
}
post(url) {
return this.submit('post', url);
}
submit(requestType, url) {
return new Promise((resolve, reject) => {
axios[requestType](url, this.data())
.then(response => {
this.onSuccess(response.data);
resolve(response.data);
})
.catch(error => {
this.onFail(error.response.data);
reject(error.response.data);
});
});
}
onSuccess(data) {
alert(data.message);
this.reset();
}
onFail(errors) {
this.errors.record(errors);
}
}
and this is the `Vue class
` `new Vue({
el: "#form",
data: {
form: new Form({
name: '',
description: ''
})
},
methods: {
onSubmit() {
this.form.post('/admin/category');
//.then(response => alert('Item created successfully.'));
//.catch(errors => console.log(errors));
},
onSuccess(response) {
alert(response.data.message);
form.reset();
}
}
});`
and this is my HTML form
<form method="post" id="form" action="{{ url('admin/category') }}" '
#submit.prevent="onSubmit" #keydown="form.errors.clear($event.target.name)">
{{ csrf_field() }}
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" id="name" name="name"
v-model="form.name" placeholder="Name">
<span class="help is-danger"
v-if="form.errors.has('name')" v-text="form.errors.get('name')"></span>
</div>
<div class="form-group">
<label for="description">Description</label>
<textarea class="form-control" id="description" name="description"
v-model="form.description" placeholder="Description"></textarea>
<span class="help is-danger"
v-if="form.errors.has('description')"
v-text="form.errors.get('description')"></span>
</div>
<button type="submit" class="btn btn-default" :disabled="form.errors.any()">Create New Category</button>
</form>
Question:
I need to modify the code in a way that firstly it checks on client side and if it finds any errors prevent the request from being sent to the server not letting every single request to be sent to server and then displays the errors sent back from the server
You can use any type of client side validation with your setup, just before you submit the form you can take the data from the Form class and validate it with vanilla javascript or any other validation library.
Let's use validate.js as an example:
in your onSubmit method you can do:
onSubmit() {
//get all the fields
let formData = this.form.data();
//setup the constraints for validate.js
var constraints = {
name: {
presence: true
},
description: {
presence: true
}
};
//validate the fields
validate(formData, constraints); //you can use this promise to catch errors
//then submit the form to the server
this.form.post('/admin/category');
//.then(response => alert('Item created successfully.'));
//.catch(errors => console.log(errors));
},
To simplify my form validation, I try to go from this:
<div ng-class="{'field--error': form.firstname.$error.maxlength && form.firstname.$dirty}" class="field">
<label for="firstname" class="field__label">Firstname</label>
<input id="firstname" type="text" name="firsname" ng-model="formData.firstname" ng-maxlength="32" class="field__input">
</div>
to this:
<div field-error="{fieldName: 'firsname'}" class="field">
<label for="firstname" class="field__label">Firstname</label>
<input id="firstname" type="text" name="firsname" ng-model="formData.firstname" ng-maxlength="32" class="field__input">
</div>
I used a fieldError directive to make validation easier (especially dirty and touched). The directive gets a reference to the formController via the '^form' param:
.directive('fieldError', function fieldError(){
return {
restrict: 'A',
require: '^form',
scope: {
fieldError: '='
},
link: function( scope, elem, attrs, formCtrl ) {
var
fieldInput = formCtrl[ scope.fieldError.fieldName ],
isInError = false;
if ( fieldInput && fieldInput.$dirty ) {
// validation process goes here
}
if ( isInError ) {
elem.addClass('field--error');
} else {
elem.removeClass('field--error');
}
}
};
})
Issue: the link function isn't called when typing text in the input.
Maybe I have to use a watcher, but I heard this is bad practice.
EDIT
following this post I updated my directive:
link: function( scope, elem, attrs, formCtrl ) {
var fieldInputPath = formCtrl.$name + '.' + scope.fieldError.fieldName + '.$invalid';
// fieldInputPath = 'form.firstname.$invalid'
scope.$watch( fieldInputPath, function( n, o ) {
// never fired
} );
}
But the watcher is never fired. I put a breakpoint in devtool, fieldInputPath is good.
Any thoughts?
I have the following html and two functions, used to add a custom editor to a grid with a checkbox. The checkbox is displayed correctly when first bringing up the grid using the checkBoxTemplate function, but when I try to update, the checkBoxEditor function is not called, and thus I don't get a checkbox, but rather the string "checkBoxEditor". What am I doing wrong?
<div id="dependencyGrid" data-role="grid"
data-scrollable="true"
data-editable="inline"
data-sortable="true"
data-toolbar="['create']"
data-bind="source: dependencies"
data-columns="[
{ field: 'ActiveFlag', title: 'Active', width: 30, editor: 'checkBoxEditor', template: '#=checkBoxTemplate(data.ActiveFlag)#' }
]">
</div>
checkBoxEditor = function (container, options) {
if (options.model.ActiveFlag == 1)
$('<input type="checkbox" checked=checked class="chkbx activeflag" ></input> ').appendTo(container);
else
$('<input type="checkbox" class="chkbx activeflag" ></input> ').appendTo(container);
};
checkBoxTemplate = function (input) {
if (input == 1 || input == true) {
return '<input type=checkbox checked=checked class=chkbx disabled=disabled ></input>';
}
return '<input type=checkbox class=chkbx disabled=disabled ></input>';
}
This is the correct, basic way to do this. I just didn't have my checkBoxEditor function defined where it could be accessed by the html... So, it you want to set up a custom editor for a checkbox, this should work for ya.