I have installed programr. I followed tutorial from this site http://dreamingechoes.github.io/bot/ruby/rails/conversational-bot-ruby-on-rails/
bot.rb
require 'programr'
brains = Dir.glob("lib/bot/*")
BOT = ProgramR::Facade.new
BOT.learn(brains)
application_controller.rb
def ask_bot
reaction = BOT.get_reaction(params[:query])
render json: { response: reaction.present? ? reaction : "I don't have an answer to that" }
end
bot.aiml
<?xml version="1.0" encoding="UTF-8"?>
<aiml version="1.0" xmlns="http://alicebot.org/2001/AIML-1.0.1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://alicebot.org/2001/AIML-1.0.1 http://aitools.org/aiml/schema/AIML.xsd">
<category>
<pattern>Hello *</pattern>
<template>
Hey, how can I help you?
</template>
</category>
<category>
<pattern>*bye</pattern>
<template>
Always here for you!
</template>
</category>
<category>
<pattern>What payment methods do you accept?</pattern>
<template>
We accept Visa, MasterCard and American Express.
</template>
</category>
</aiml>
view:
<div class="alert alert-info">
×
<strong>Info!</strong> Type something on the text input and hit the <strong>GO</strong> button to get a response.
</div>
<div class="bs-callout bs-callout-info bot-response hide" id="callout-alerts-no-default">
<h4>Bot says:</h4>
<p id="bot-response"> </p>
</div>
<div class="row home-row">
<div class="col-lg-12">
<div class="input-group">
<input id="query" type="text" class="form-control" placeholder="Say something to the bot...">
<span class="input-group-btn">
<button id="ask" class="btn btn-default" type="button">GO</button>
</span>
</div>
</div>
</div>
application.js
$(document).ready(function(){
$('#ask').on('click', function(event) {
$.ajax({
url: '/ask_bot',
type: 'json',
method: 'get',
data: { query: $('#query').val() },
success: function(data) {
$('.bot-response').removeClass('hide');
$('#bot-response').html(data['response']);
$('#query').val('');
}
});
});
});
If i copy a pattern and paste in the form, the GO button does nothing. Please help...thanks!
Most probably what you'll have to use is the DOMContentLoaded in order to check when the DOM has finished loading, this way you can wrap the listener for the #ask button and the AJAX function, without having to modify your "requires" in the application.js file, nor to have to include them as script tags in your views.
You could try with something like:
document.addEventListener('DOMContentLoaded', function () {
...
});
And inside to put your JS code, which would remain as:
document.addEventListener('DOMContentLoaded', function () {
$('#ask').on('click', function(event) {
$.ajax({
url: '/ask_bot',
type: 'json',
method: 'get',
data: { query: $('#query').val() },
success: function(data) {
$('.bot-response').removeClass('hide');
$('#bot-response').html(data['response']);
$('#query').val('');
}
});
});
$('[data-toggle="tooltip"]').tooltip();
});
Also you could add the specific custom.js for the specific controller and action in which is being used, that's the reason of the Uncaught TypeError: Cannot read property 'getContext' of null error, because such elements barChart and barChart2 are in the back_office#index.
Related
I need to Add data & image file in a same post request using alpine js.
I think it is a little bit late. But, someone else might need take benefit from this answer in the future.
You can use Javascript's FormData to handle both data and file.
Bellow, I am copying a part from my application to show the full process of actually uploading image with Alpine JS and sending it as part of Form Data to your API end.
HTML Part:
<form method="post" enctype="multipart/form-data" #submit.prevent="$store.app.submitData()">
<div class="row mb-4">
<div class="form-group col-md-4">
<label>App Name</label>
<input type="text" name="name" class="form-control" x-model="$store.app.form.name">
</div>
<div class="form-group col-md-4">
<label>Slug</label>
<input type="text" name="name" class="form-control" x-model="$store.app.form.slug">
</div>
<div class="form-group col-md-4">
<label>Icon/Logo</label>
<input type="file" name="image_icon" class="form-control" x-on:change="$store.app.selectFile($event)" accept="image/png, image/jpg, image/jpeg">
</div>
</div>
<div class="row">
<div class="col-md-12 text-end mt-3">
<button type="submit" class="btn btn-lg btn-primary mb-5" :disabled="$store.app.loading">
<span class="indicator-label">Save</span>
</button>
</div>
</div>
</form>
Alpine JS Part:
<script>
document.addEventListener('alpine:init', () => {
Alpine.store('app', {
loading: false,
form: {
name: '',
image_icon: '',
slug: ''
},
selectFile(event) {
this.form.image_icon = event.target.files[0]
},
submitData() {
//Create an instance of FormData
const data = new FormData()
let url = '/application'
// Append the form object data by mapping through them
Object.keys(this.form).map((key, index) => {
data.append(key, this. Form[key])
});
this.loading = true
fetch(url, {
method: 'POST',
headers: {
'Accept': 'application/json',
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
body: data
})
.then(response => {
//...
})
.finally(() => {
this. Loading = false
});
}
})
})
</script>
Please note that I have used store in this example, you can use Alpine Data, function or inline x-data as you please.
Appending to the form data just requires a key and value pair, for example;
const data = new FormData();
data.append('name', 'John');
data.append('surname', 'Doe');
I hope this helps.
Alright so I am trying to bind this vue components to a class name so it triggers on every element that has this class but what happens is that it only works with the first element and not with other ones
<div class="__comment_post">
<textarea></textarea>
<input type="submit" v-on:click="submitComment" /> <!-- submit comment being only triggered on this one -->
</div>
<div class="__comment_post">
<textarea></textarea>
<input type="submit" v-on:click="submitComment" />
</div>
<div class="__comment_post">
<textarea></textarea>
<input type="submit" v-on:click="submitComment" />
</div>
As you can see above, I've got 3 divs with class __comment_post so naturally submitComment should be bound to all these 3 divs but what happens is that submitComment is being triggered only on the first one
var app = new Vue({
el:".__comment_post",
data: {
comment: ""
},
methods: {
submitComment: function() {
console.log("Test");
}
}
});
Here is a little example you and others can follow in order to bind vue instance to class names.
Lets say, you would like to bind Vue to multiple existing <div class="comment"> element in HTML.
HTML:
<div class="comment" data-id="1">
<div>
<div class="comment" data-id="2">
<div>
Now, you can try the following logic/code to your example.
JS:
var comments = {
"1": {"content": "Comment 1"},
"2": {"content": "Comment 2"}
}
$('.comment').each(function () {
var $el = $(this)
var id = $el.attr('data-id')
var data = comments[id]
new Vue({
el: this,
data: data,
template: '<div class="comment">{{ content }}<div>'
})
})
I hope this will answer your question :)
The vue instance is mounted on the first found DOM element with the css selector passed to the el option. So the rest two div have no vue instances mounted on them.
So wrap your divs with a wrapper div and mount the vue instance on that wrapper
<div id="app">
<div class="__comment_post">
<textarea></textarea>
<input type="submit" v-on:click="submitComment" /> <!-- submit comment being only triggered on this one -->
</div>
<div class="__comment_post">
<textarea></textarea>
<input type="submit" v-on:click="submitComment" />
</div>
<div class="__comment_post">
<textarea></textarea>
<input type="submit" v-on:click="submitComment" />
</div>
script
var app = new Vue({
el:"#app",
data: {
comment: ""
},
methods: {
submitComment: function() {
console.log("Test");
}
}
});
About the issue
I am using Laravel 5.6.7 with vue.js. vee-validate is being used for validation
When the form loads, it shows validation error messages. User did not even click the submit button. Below is the screenshot.
Code
<template>
<div>
<form role="form">
<input v-validate data-vv-rules="required" type="text"
v-model="UpdateForm.First_Name">
<p v-if="errors.has('First Name')">{{ errors.first('First Name') }}</p>
<button type="button">
Update Profile
</button>
</form>
</div>
</template>
<script>
export default {
data() {
return {
UpdateForm: {
First_Name: ''
}
}
},
created() {
this.GetProfile();
},
methods: {
GetProfile() {
axios.post("some api url", {}).then(response => {
this.UpdateForm.First_Name = response.data.Data.First_Name;
});
}
}
}
</script>
Could I get rid of validation error messages on form load?
This is not the expected behavior. For initial validating you need to inform it with v-validate.initial.
Maybe you are defining this to happen when declaring v-validate or in other place.
Vue.use(VeeValidate);
new Vue({
el: '#demo'
})
.is-danger{
color: red;
}
<script src="https://unpkg.com/vue"></script>
<script src="https://cdn.jsdelivr.net/npm/vee-validate#latest/dist/vee-validate.js"></script>
<div id="demo">
<label>This one needs touching</label>
<input type="text" name="name" v-validate="'required'">
<div v-show="errors.has('name')" class="is-danger">Errors: {{ errors.first('name') }}</div>
<br/>
<label>This one does not need touching</label>
<input name="name2" v-validate.initial="'required'" type="text">
<div v-show="errors.has('name2')" class="is-danger">{{ errors.first('name2') }}</div>
</div>
Changed
this.editForm.First_Name = Data.User.First_Name;
to
if(Data.User.First_Name != null && Data.User.First_Name != "") {
this.editForm.First_Name = Data.User.First_Name;
}
and validation is working fine now. Basically the variable is not initialized.
I want to add a dropzone inside an existing form but it doesn't seem to work.
When I view the console I get error throw new Error("No URL provided"). When I click upload I get no preview either - all I get is a normal file input.
<link href="../dropzone.css" rel="stylesheet">
<form action="/" enctype="multipart/form-data" method="POST">
<input type="text" id ="Username" name ="Username" />
<div class="dropzone" id="my-dropzone" name="mainFileUploader">
<div class="fallback">
<input name="file" type="file" />
</div>
</div>
<div>
<button type="submit" id="submit"> upload </button>
</div>
</form>
<script src="../jquery.min.js"></script>
<script src="../dropzone.js"></script>
<script>
$("my-dropzone").dropzone({
url: "/file/upload",
paramName: "file"
});
</script>
No url provided error is because $("my-dropzone") is wrong instead it must be $('#mydropzone')
dropzone along with other form, yes this is very much possible, you have to post the data using the URL provided in the dropzone not in the form action. That means all your form data along with the files uploaded shall be posted back to the url provided for the dropzone. A simple untested solution is as below;
<link href="../dropzone.css" rel="stylesheet">
<form action="/" enctype="multipart/form-data" method="POST">
<input type="text" id ="Username" name ="Username" />
<div class="dropzone" id="my-dropzone" name="mainFileUploader">
<div id="previewDiv></div>
<div class="fallback">
<input name="file" type="file" />
</div>
</div>
<div>
<button type="submit" id="submitForm"> upload </button>
</div>
</form>
<script src="../jquery.min.js"></script>
<script src="../dropzone.js"></script>
<script>
$("#mydropzone").dropzone({
url: "/<controller>/action/" ,
autoProcessQueue: false,
uploadMultiple: true, //if you want more than a file to be uploaded
addRemoveLinks:true,
maxFiles: 10,
previewsContainer: '#previewDiv',
init: function () {
var submitButton = document.querySelector("#submitForm");
var wrapperThis = this;
submitButton.addEventListener("click", function () {
wrapperThis.processQueue();
});
this.on("addedfile", function (file) {
// Create the remove button
var removeButton = Dropzone.createElement("<button class="yourclass"> Remove File</button>");
// Listen to the click event
removeButton.addEventListener("click", function (e) {
// Make sure the button click doesn't submit the form:
e.preventDefault();
e.stopPropagation();
// Remove the file preview.
wrapperThis.removeFile(file);
});
file.previewElement.appendChild(removeButton);
});
// Also if you want to post any additional data, you can do it here
this.on('sending', function (data, xhr, formData) {
formData.append("PKId", $("#PKId").val());
});
this.on("maxfilesexceeded", function(file) {
alert('max files exceeded');
// handle max+1 file.
});
}
});
</script>
The script where you initialize dropzone can be inside $document.ready or wrap it as a function and call when you want to initialize it.
Happy coding!!
I am a newbie and tried to do the laziest way to do a file upload using emberjs, jquery and formdata(IE10+). The code might look stupid, but it worked.
Here is what i got. Can you please take a look and give some suggestions. Am i doing it wrong?
<script type="text/x-handlebars" data-template-name="posts">
<form role="form" enctype="multipart/form-data" method="post" id="fileinfo" {{action 'createPost' on='submit'}}>
{{input type="text" value=newPost id="newPost" placeholder="Post" class="form-control"}}
{{input type="file" id="inputFile" class="form-control" name="file"}}
<button type="submit" class="btn btn-default" >Submit</button>
</form>
</script>
App.PostsController = Ember.ArrayController.extend({
actions: {
createPost: function(){
var fd = new FormData(document.getElementById("fileinfo"));
fd.append("postContent", this.get('newPost'));
this.set('newPost', ''); //reset text field
$('#inputFile').val(''); //reset fileinput field
Ember.$.ajax({
url: "http://localhost:3000/posts",
type: "POST",
data: fd,
processData: false, // tell jQuery not to process the data
contentType: false, // tell jQuery not to set contentType
});
}
}
});