Bootstrap typeahead not showing results - laravel

I'm using https://github.com/bassjobsen/Bootstrap-3-Typeahead with Laravel 5.3.
I was using the twitter version before hand which worked fine, except the styles were broken. So I switched to this version but the drop down isn't being rendered. There are no errors either in the console.
If I open the network tab in dev tools, I can see that the request being made and data is being successfully returned. It's just not rendering the suggestion dropdown box.
Anyone know why that could be?
<input type="text" id="search" data-provide="typeahead" autocomplete="off">
var engine = new Bloodhound({
remote: {
url: '/find?q=%QUERY%',
wildcard: '%QUERY%'
},
datumTokenizer: Bloodhound.tokenizers.whitespace,
queryTokenizer: Bloodhound.tokenizers.whitespace
});
engine.initialize();
$("#search").typeahead({
hint: true,
highlight: true,
minLength: 0,
source:engine.ttAdapter()
});

Check out my jsfiddle https://jsfiddle.net/yqy995wv/
HTML
<div id="remote">
<input class="typeahead" type="text" placeholder="Oscar winners for Best Picture">
</div>
JS
jQuery(document).ready(function($){
var bestPictures = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
url: 'https://twitter.github.io/typeahead.js/data/films/queries/%QUERY.json',
wildcard: '%QUERY'
}
});
$('#remote .typeahead').typeahead(null, {
name: 'best-pictures',
display: 'value',
source: bestPictures
});
});
Your JSON response should be like
[
{
"value": "All Quiet on the Western Front",
},
{
"value": "Gentleman's Agreement",
},
{
"value": "All the Kings Men",
},
{
"value": "All About Eve",
},
{
"value": "An American in Paris",
},
{
"value": "Around the World in 80 Days",
},
{
"value": "The Apartment",
}
]

Related

Select 2 Wrapped component duplicated when loading options

I've created a wrapped vue component in laravel in order to wrap jQuery select2 element.
Based in this code.
When the values in select.options change, the select element is duplicated. Like the following image.
The selection only works in the second select.
I don't know what is the problem, I add below the code I have made and the content of the options variable.
select2.vue
<template>
<div>
<select>
<slot></slot>
</select>
</div>
</template>
<script>
export default {
name: "select2",
props: ['options', 'value'],
mounted: function () {
let vm = this
$(this.$el)
// init select2
.select2({ data: this.options })
.val(this.value)
.trigger('change')
// emit event on change.
.on('change', function () {
vm.$emit('input', this.value)
})
},
watch: {
value: function (value) {
// update value
$(this.$el)
.val(value)
.trigger('change')
},
options: function (options) {
// update options
$(this.$el).empty().select2({ data: options })
}
},
destroyed: function () {
$(this.$el).off().select2('destroy')
}
}
</script>
<style scoped>
</style>
blade file call
<select2 :options="select.options" v-model="select.value"></select2>
select.options data
[
{
"text": "Group 1",
"children": [
{
"id": 1,
"text": "Element 1"
},
{
"id": 2,
"text": "Element 2"
}
]
},
{
"text": "Group 2",
"children": [
{
"id": 3,
"text": "Element 3"
},
{
"id": 4,
"text": "Element 4"
}
]
}
]
I tried for a while to reproduce the problem you were having, without any success.
I noticed a couple of things that might help you:
this.$el refers to the div in your example, where as the examples I've seen use select.
Try and avoid using the same names for properties and variables, as this makes it confusing options: function (options) {
I've included a snippet below in case it helps.
Vue.config.productionTip = false;
Vue.config.devtools = false;
Vue.component("select2", {
template: "<select style='width: 100%'></select>",
props: ['options', 'value'],
mounted: function() {
let vm = this
$(this.$el)
.select2({
data: this.options
})
.val(this.value)
.trigger('change')
.on('change', function() {
vm.$emit('input', this.value)
})
},
watch: {
value: function(value) {
$(this.$el)
.val(value)
.trigger('change')
},
options: function(val) {
$(this.$el).empty().select2({
data: val
})
}
},
destroyed: function() {
$(this.$el).off().select2('destroy')
}
});
new Vue({
el: "#app",
data: () => {
return {
selected: null,
options: [{
"text": "Group 1",
"children": [{
"id": 1,
"text": "Element 1"
},
{
"id": 2,
"text": "Element 2"
}
]
},
{
"text": "Group 2",
"children": [{
"id": 3,
"text": "Element 3"
},
{
"id": 4,
"text": "Element 4"
}
]
}
]
}
},
methods: {
modifyOptions() {
this.options = [{
"text": "Group 1",
"children": [{
"id": 4,
"text": "Element 1"
},
{
"id": 6,
"text": "Element 2"
}
]
}];
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/select2#4.0.13/dist/css/select2.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/select2#4.0.13/dist/js/select2.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div>
<select2 :options="options" v-model="selected"></select2>
<div>
Selected: {{selected}}
</div>
<button type="button" #click="modifyOptions">Modify Options</button>
</div>
</div>

Vuejs / laravel image upload receiving empty array

I have looked at a lot of Q&A on stackoverflow but I can't figure out what I'm doing wrong.
I am building a webshop (to improve my coding), currently working on Add Product bit.
The idea is that I can add a product, which can have multiple 'products'. For example, a T-shirt is one product, but the same t-shirt can be red/green color small/medium size and those have their own stock.
HTML in Vue component
<label class="btn-bs-file btn btn-primary">
Add picture
<input type="file" multiple="multiple" #change="onFileChange($event, index)"/>
</label>
<div v-for="image in form.products[index].files" :key="image.id">
<img :src="image.preview" />
</div>
JS
onFileChange(e, index) {
var files = e.target.files || e.dataTransfer.files;
if (!files.length)
return;
this.createImage(files[0], index);
},
createImage(file, index) {
var reader = new FileReader();
var vm = this
var formData = new FormData()
formData.append('file', file)
reader.onload = (e) => {
vm.form.products[index].files.push({
file: formData,
preview: e.target.result
});
};
reader.readAsDataURL(file);
},
submit: function() {
let vm = this
this.$api.post('products', this.form,
{
headers: {
'Content-Type': 'multipart/form-data'
}
})
.then(res => {
console.log(res.data)
// vm.upload(res.data)
})
.catch(error => {
this.message('error', error, 'Error')
console.log(error)
})
},
PHP
public function store(Request $request)
{
return response()->json($request->all());
}
This is structure (and the response). As you can see, the file is an empty array and I want the actual file here.
{
"name": "Random Name",
"brand": null,
"description": null",
"categories": [],
"note": null,
"products": [
{
"attributes": [],
"color": "random",
"state": "active",
"price": "12",
"files": [
{
"file": [],
"preview": "data:image/png;base64,"
}
]
}
]
}
When I look in my browser (vuejs plugin) it shows me this:
So I guess the formData is in there, but I'm not sure if this is a correct way of doing this and how I would get the formData in the backend.
(I've been at this for over 10 hours, I tried a lot of different things in both backend and frontend, too much to list here..)

How to implement Quill Emojis in vue2editor?

I tried to add Quill Emojis to editor but I am getting console error as
Uncaught ReferenceError: Quill is not defined
I am using Laravel 5.6 and vue js and definately new to vue and its components so I may sound silly to you but for the past 3 days I am searching on the google for the solution and even contacted author of vue2editor on github here is the link
This is what I have tried so far:
vue2editor.vue
<template>
<div id="app">
<vue-editor v-model="content"></vue-editor>
</div>
</template>
<script>
import { VueEditor, Quill } from 'vue2-editor';
import Emoji from 'quill-emoji/dist/quill-emoji';
Quill.register('modules/quill-emoji', Emoji);
export default {
name: 'vue2editor',
components: { VueEditor },
data() {
return {
content: "<h1>Some initial content</h1>",
editorSettings: {
modules: {
toolbar: {
container: [
[{'size': ['small', false, 'large']}],
['bold', 'italic', 'underline', 'strike'],
['blockquote', 'code-block'],
[{ 'header': 1 }, { 'header': 2 }],
[{ 'list': 'ordered' }, { 'list': 'bullet' }],
[{ 'script': 'sub' }, { 'script': 'super' }],
[{ 'indent': '-1' }, { 'indent': '+1' }],
[{ 'direction': 'rtl' }],
[{ 'header': [1, 2, 3, 4, 5, 6, false] }],
[{ 'color': [] }, { 'background': [] }],
[{ 'font': [] }],
[{ 'align': [] }],
['clean'],
['link', 'image', 'video'],
['emoji'],
],
handlers: {
'emoji': function () {}
},
},
toolbar_emoji: true,
short_name_emoji: true,
textarea_emoji:true,
},
},
text: null,
};
},
};
</script>
I even tried the method mentioned by one of the user on github for Quill-Emoji, here is the link.
I came here with lots of hopes; if anyone here is to help me out, at least tell me what I am missing will be more than a help for me.
Quill.register({
'formats/emoji': Emoji.EmojiBlot,
'modules/short_name_emoji': Emoji.ShortNameEmoji,
'modules/toolbar_emoji': Emoji.ToolbarEmoji,
'modules/textarea_emoji': Emoji.TextAreaEmoji}, true);
you need register the model, add the up code to you code.
Edit:
//1) Add plugin to laravel mix
const mix = require('laravel-mix')
mix.webpackConfig(webpack => {
return {
plugins: [
new webpack.ProvidePlugin({
"window.Quill": "quill/dist/quill.js",
Quill: "quill/dist/quill.js"
})
]
};
});
//2 example vue file
<template>
<div class="mt-1">
<vue-editor
ref="editor"
v-model="content"
:editor-toolbar="customToolbar"
:editorOptions="editorSettings"
/>
</div>
</template>
<script>
import { VueEditor, Quill } from "vue2-editor";
import Emoji from "quill-emoji/dist/quill-emoji";
Quill.register("modules/emoji", Emoji);
export default {
components: {
VueEditor,
},
props: {
bubble: Object,
contentCol: {
type: String,
},
},
data() {
return {
edit: false,
content: "<b>Content is here</b>",
customToolbar: [["bold", "italic", "underline"], ["link"], ["emoji"]],
editorSettings: {
modules: {
"emoji-toolbar": true,
"emoji-textarea": true,
"emoji-shortname": true,
},
},
};
},
beforeDestroy() {},
};
</script>
<style src="quill-emoji/dist/quill-emoji.css"/>

Amchart doesn't show up when listed with html <select> tag

My previous issue was to get json data attached to amcharts, after struggling for a while, I got it running the way I want. But when I move it from test page to page where it would be listed with other charts it doesn't seem to work. When I click on blank chart this error appears in the console
Uncaught TypeError: Cannot read property 'length' of undefined
at Object.xToIndex (serial.js:14)
at b.handleCursorMove (serial.js:8)
at Object.a.inherits.b.fire (amcharts.js:1)
at Object.dispatchMovedEvent (amcharts.js:27)
at Object.handleMouseDown (amcharts.js:26)
at b.handleMouseDown (serial.js:1)
at HTMLDivElement.<anonymous> (amcharts.js:18)
Below is the code which is working when I have it on separate page
var chart = AmCharts.makeChart("chart1", {
"type": "serial",
"dataLoader": {
"url": "#myURL"
},
"valueAxes": [{
"title": "Load Average",
"gridColor": "#FFFFFF",
"gridAlpha": 0.2,
"dashLength": 0
}],
"gridAboveGraphs": true,
"startDuration": 1,
"graphs": [{
"balloonText": "[[title]] of [[category]]:[[value]]",
"id": "AmGraph-1",
"lineThickness": 3,
"valueField": "LoadAverage"
}],
"chartCursor": {
"categoryBalloonEnabled": false,
"cursorAlpha": 0,
"zoomable": false
},
"categoryField": "EndTimeLoop",
"categoryAxis": {
"title": "End Time Loop",
"gridPosition": "start",
"gridAlpha": 0,
"tickPosition": "start",
"tickLength": 20,
"labelRotation": 90
}
});
function setDataSet(dataset_url) {
AmCharts.loadFile(dataset_url, {}, function(data) {
chart.dataProvider = AmCharts.parseJSON(data);
chart.validateData();
});
};
this is the part where select happens in html side
<div class="chartWrapper" id="chartSingleTest1">
<select onchange="showChart(this.options[this.selectedIndex].value);">
<option value="chart1">Chart #1</option>
<option value="chart2">Chart #2</option>
<option value="chart3">Chart #3</option>
</select>
<div id="chart1" class="chartBoxSingle" style="display: none;"></div>
<div id="chart2" class="chartBoxSingle" style="display: none;"></div>
<div id="chart3" class="chartBoxSingle" style="display: none;"></div>
</div>
and here is js part where selects the first option on page load
var currentChart;
function showChart( divid ) {
if (currentChart !== undefined)
currentChart.style.display = "none";
if ( divid ) {
currentChart = document.getElementById(divid);
currentChart.style.display = "block";
}
else {
currentChart = undefined;
}
}
$(document).ready(function() { showChart('chart1'); });
You have to call the chart object's validateSize method when toggling the display of a chart from none to block as shown in this example that uses tabs. Here's another example using your structure:
var charts = {};
charts["chart1"] = AmCharts.makeChart("chart1", {
type: "serial",
dataProvider: [{
"value": 1,
"category": "Category 1"
}, {
"value": 2,
"category": "Category 2"
}, {
"value": 3,
"category": "Category 3"
}],
categoryField: "category",
graphs: [{
valueField: "value",
type: "column",
fillAlphas: .8
}]
});
charts["chart2"] = AmCharts.makeChart("chart2", {
type: "pie",
dataProvider: [{
"value": 2,
"title": "Slice 1"
}, {
"value": 2,
"title": "Slice 2"
}, {
"value": 2,
"category": "Slice 3"
}],
titleField: "title",
valueField: "value"
});
var currentChart;
function showChart(divid) {
if (currentChart !== undefined)
currentChart.style.display = "none";
if (divid) {
currentChart = document.getElementById(divid);
currentChart.style.display = "block";
charts[divid].validateSize();
} else {
currentChart = undefined;
}
}
$(document).ready(function() {
showChart('chart1');
});
.chartBoxSingle {
width: 100%;
height: 400px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script type="text/javascript" src="//www.amcharts.com/lib/3/amcharts.js"></script>
<script type="text/javascript" src="//www.amcharts.com/lib/3/serial.js"></script>
<script type="text/javascript" src="//www.amcharts.com/lib/3/pie.js"></script>
<div class="chartWrapper" id="chartSingleTest1">
<select onchange="showChart(this.options[this.selectedIndex].value);">
<option value="chart1">Chart #1</option>
<option value="chart2">Chart #2</option>
</select>
<div id="chart1" class="chartBoxSingle" style="display: none;"></div>
<div id="chart2" class="chartBoxSingle" style="display: none;"></div>
</div>

Conditional and custom validation on Add / Edit form fields when using Kendo grid custom popup editor template

I am using a custom template for kendo grid popup Add / Edit form. Here is my working DEMO
I want to implement conditional validation on form fields such as if any value is entered for Address (not left empty) then the fields City and Postal Code should become required, otherwise they can be empty. Also I want to ise a custom validation rule for PostCode so that its length should always be equal to 4 else it should show a custom error message as "Postcode must be four digits"
I have referred these links:
Validation rules in datasource.model
Custom validation rules and error messages
but I can't figure out how can I implement validations in my datasource model?
Here is my code:
HTML:
<h3>I want to implement conditional validation on Add/Edit form such as if any value is entered for Address then the fields City and Postal Code should become required</h3>
<div id="grid"></div>
<script id="popup-editor" type="text/x-kendo-template">
<p>
<label>Name:<input name="name" required /></label>
</p>
<p>
<label>Age: <input data-role="numerictextbox" name="age" required /></label>
</p>
<p>
<label>Address: <input name="address"/></label>
</p>
<p>
<label>City: <input name="city"/></label>
</p>
<p>
<label>Post Code: <input name="postcode"/></label>
</p>
</script>
JS:
$("#grid").kendoGrid({
columns: [
{ field: "name" },
{ field: "age" },
{ command: "edit" }
],
dataSource: {
data: [
{ id: 1, name: "Jane Doe", age: 30 },
{ id: 2, name: "John Doe", age: 33 }
],
schema: {
model: { id: "id" },
fields: {
name:{},
age:{},
address:{},
city:{},
postcode:{},
},
}
},
editable: {
mode: "popup",
template: kendo.template($("#popup-editor").html())
},
toolbar: [{ name: 'create', text: 'Add' }]
});
If i were to do that, i would do these approach where
I will create a custom validator
Override the edit(grid) function place the validator there
Override the save(grid) function use validator.validate() before saving
Here is an example in dojo
basically this is the grid code:
var validator;
$("#grid").kendoGrid({
columns: [
{ field: "name" },
{ field: "age" },
{ command: "edit" }
],
dataSource: {
data: [
{ id: 1, name: "Jane Doe", age: 30 },
{ id: 2, name: "John Doe", age: 33 }
],
schema: {
model: { id: "id" },
fields: {
name:{},
age:{},
address:{},
city:{},
postcode:{},
},
}
},
save: function(e) {
if(!validator.data("kendoValidator").validate()){
e.preventDefault();
}
},
edit: function(){
validator = $("#test-form").kendoValidator({
validateOnBlur: false,
rules: {
matches: function(input) {
var requiredIfNotNull = input.data('test');
// if the `data-test attribute was found`
if (requiredIfNotNull) {
// get the input requiredIfNotNull
var isFilled = $(requiredIfNotNull);
// trim the values and check them
if ( $.trim(isFilled.val()) !== "" ) {
if($.trim(input.val()) !== ""){
// the fields match
return true;
}else{
return false;
}
}
// don't perform any match validation on the input since the requiredIf
return true;
}
// don't perform any match validation on the input
return true;
}
},
messages: {
email: "That does not appear to be a valid email address",
matches: function(input) {
return input.data("testMsg");
}
}
});
},
editable: {
mode: "popup",
template: kendo.template($("#popup-editor").html())
},
toolbar: [{ name: 'create', text: 'Add' }]
});
ps: i used to many if statement, you could simplify it i think
Here is the DEMO how I implemented it:
HTML:
<div id="grid"></div>
<script id="popup-editor" type="text/x-kendo-template">
<div id="myForm">
<p>
<label>Name:<input name="name" required /></label>
</p>
<p>
<label>Age: <input data-role="numerictextbox" name="age" required /></label>
</p>
<p>
<label>Address: <input name="address" id="address"/></label>
</p>
<p>
<label>City: <input name="city" id="city"/></label>
</p>
<p>
<label>Post Code: <input name="postcode" id="postcode"/></label>
<!--<span class="k-invalid-msg" data-for="postcode"></span>-->
</p>
</div>
</script>
JS:
var validator;
$("#grid").kendoGrid({
columns: [
{ field: "name" },
{ field: "age" },
{ field: "address" },
{ field: "city" },
{ field: "postcode" },
{ command: "edit" }
],
dataSource: {
data: [
{ id: 1, name: "Jane Doe", age: 30, address:'Addr', city:"city", postcode: '1234' },
{ id: 2, name: "John Doe", age: 33, address:'Addr11', city:"city11", postcode: '4321' }
],
schema: {
model: { id: "id" },
fields: {
name:{},
age:{},
address:{},
city:{},
postcode:{},
},
}
},
editable: {
mode: "popup",
template: kendo.template($("#popup-editor").html())
},
toolbar: [{ name: 'create', text: 'Add' }],
save: function(e) {//alert('save clicked');
if(!validator.validate()) {
e.preventDefault();
}
},
edit: function(e){
//alert('edit clicked');
validator = $("#myForm").kendoValidator({
messages: {
postcode: "Please enter a four digit Postal Code"
},
rules: {
postcode: function(input) {
//console.log(input);
if (input.is("[name='address']"))
{
if (input.val() != '')
{
$('#city, #postcode').attr('required', 'required');
//return false;
}
else
{
$('#city, #postcode').removeAttr("required");
}
}
else if (input.is("[name='postcode']")) {
if ($('#address').val() != '' && input.val().length != 4)
return false;
}
return true;
}
},
}).data("kendoValidator");
},
});

Resources