My webpage is receiving through AJAX GET requests Arrays with strings, and a Boolean.
The objects within the array are displayed subsequently to shape a chat app, the received array represents messages to display in a chatbox. However, some of the messages are bot's answers, stored as a user message.
Therefore, to recognize such message, I added a Boolean Value (bot=True : This is a bot answer). Such message has to be displayed on the right of the chatbox, when user messages are diplayed on the left. My code is brute forcing the left side of the chatbox, whatever the boolean value.
HTML:
<div id="display" class="chatbox"></div>
CSS:
.chat {
border-top: 1px solid #CCC;
margin-top: 1em;
border-radius: 2px;
color: white;
padding-top: 1em;
padding-bottom: 1em;
display: flex;
flex-direction: column;
}
JS:
<script>
$(document).ready(function() {
function imgMarkup(model) {
if (model.mediasrc) {
return `<img class='imgchat' src=../static/${model.mediasrc}.png/>`
}
return '';
}
setInterval(function() {
$.ajax({
type: 'GET',
url: "/checkview",
success: function go(response) {
console.log(response);
$("#display").empty();
for (var model of response.models_to_return) {
const temp = `
<div class='chat'>
<span class='time-left'>${model.datetime}</span>
<b>${model.user_id}</b>
<p>${model.room}</p>
${imgMarkup(model)}
</div>`;
$("#display").append(temp);
}
},
error: function(response) {
//alert('An error occured')
}
});
}, 1000);
})
</script>
I would like to be able to add a second class to my .chat (css), like class="chat right" depending on the boolean value of the variable 'bot' from the AJAX response.
Use a variable to hold the additional class, and set it conditionally based on model.bot.
$(document).ready(function() {
function imgMarkup(model) {
if (model.mediasrc) {
return `<img class='imgchat' src=../static/${model.mediasrc}.png/>`
}
return '';
}
setInterval(function() {
$.ajax({
type: 'GET',
url: "/checkview",
success: function go(response) {
console.log(response);
$("#display").empty();
for (var model of response.models_to_return) {
let botclass = model.bot ? 'right' : '';
const temp = `
<div class='chat ${botclass}'>
<span class='time-left'>${model.datetime}</span>
<b>${model.user_id}</b>
<p>${model.room}</p>
${imgMarkup(model)}
</div>`;
$("#display").append(temp);
}
},
error: function(response) {
//alert('An error occured')
}
});
}, 1000);
})
Related
I'm developing a chat bot (v4 using MS Azure bot framework & QnAmaker),
I've added a feature in that, i.e. while the users starts typing the questions, the bot will get prompt and show the relevant questions form the QnAmaker , and the user can select one of them , then that particular question will sent to the bot.
Following is the full code which I'm using,
<html>
<body>
<div id="webchat" role="main"></div>
<script>
(async function () {
const styleOptions = {
hideUploadButton: true,
bubbleBackground: '#D8F4FF',
bubbleFromUserBackground: '#E8E8E8',
botAvatarImage: '../botavatar.PNG',
botAvatarInitials: 'bot',
userAvatarInitials: initial,
userAvatarImage: userimg,
rootHeight: '100%',
rootWidth: '50%'
};
const styleSet = window.WebChat.createStyleSet({
bubbleBackground: 'rgba(0, 0, 255, .1)',
bubbleFromUserBackground: 'rgba(0, 255, 0, .1)'
});
styleSet.textContent = {
fontFamily: "'Comic Sans MS', 'Arial', sans-serif",
fontWeight: 'bold'
};
const secret = secret;
const res = await fetch('https://directline.botframework.com/v3/directline/tokens/generate',
{
headers: {
Authorization: `Bearer ${secret}`,
},
method: 'POST'
});
const { token } = await res.json();
const store = window.WebChat.createStore(
{},
({ dispatch }) => next => action => {
if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED') {
dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'webchat/join',
}
});
}
return next(action);
}
);
window.WebChat.renderWebChat({
directLine: window.WebChat.createDirectLine({ token }),
store,
styleOptions,
userID: emailid,
username: fullname,
locale: 'en-US',
userAvatarInitials: initial
}, document.getElementById('webchat'));
document.querySelector('#webchat > *').focus();
document.querySelectorAll('[aria-label="Sendbox"]')[0].placeholder = "Type your question and press enter";
$("[aria-label='Sendbox']").keypress(function () {
if ($("[aria-label='Sendbox']")[0].defaultValue.length > 4) {
getquestion(this.value);
} else {
$('#ques').remove();
}
});
$('div.probing').click(function () { alert(this.innerText); });
$('div.probing').click(function () {
document.querySelectorAll('[aria-label="Sendbox"]')[0].value = (this.innerText);
document.querySelectorAll('[aria-label="Sendbox"]')[0].defaultValue = (this.innerText);
$('.css-115fwte').trigger('click');
$('#ques').remove();
});
})().catch(err => console.error(err));
function getquestion(value) {
var token = secret;
var questionquery =
{
question: value,
top: 2,
scoreThreshold: 50,
"strictFilters": [
{
"name": "message",
"value": "text"
}],
}
$.ajax({
type: "POST",
url: "https://endpoint/qnamaker/knowledgebases/KBID/generateAnswer",
data: JSON.stringify(questionquery),
beforeSend: function (xhr) {
xhr.setRequestHeader('Authorization', secret);
},
dataType: "json",
contentType: "application/json",
success: function (data) {
var questions = "";
$('#ques').remove();
for (var i = 0; i < 4; i++) {
if (data.answers[0].questions[i] != null && data.answers[0].questions[i] != 'undefined')
questions = questions + "<div class='probing'>" + data.answers[0].questions[i] + "</div>";
}
$('.content').last().append("<div id='ques'>" + questions + "</div>");
$('div.probing').click(function () {
document.querySelectorAll('[aria-label="Sendbox"]')[0].value = (this.innerText);
document.querySelectorAll('[aria-label="Sendbox"]')[0].defaultValue = (this.innerText);
$('.css-115fwte').trigger('click');
$('#ques').remove();
});
},
error: function (data) {
alert(data.responseText);
}
});
}
</script>
</body>
</html>
Please check the below image of my bot with the prompted questions, it will look like this, these questions are get appended to the last reply given by the bot, after selecting the question, this div will get removed. On the next question this cycle will continue again.
Problem I'm facing is here, with the following code the value is getting entered in the input box, however the bot does not received any question, and hence it failed to answer.
$('div.probing').click(function () {
document.querySelectorAll('[aria-label="Sendbox"]')[0].value = (this.innerText);
document.querySelectorAll('[aria-label="Sendbox"]')[0].defaultValue = (this.innerText);
$('.css-115fwte').trigger('click');
$('#ques').remove();
});
With this code the value is getting entered in the input box, however the bot does not received any question, and hence it failed to answer.
this is how it will in console after adding the question by script.
Note that I've used all the required reference JS and CSS Files in my code.
So please help me with the correct approach to achieve my requirement, Thanks in Advance.
Here's a working demo that should get you started, using a similar method from the sample:
<!DOCTYPE html>
<html lang="en-US">
<head>
<title>Web Chat: Programmatic access to post activity</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!--
This CDN points to the latest official release of Web Chat. If you need to test against Web Chat's latest bits, please refer to pointing to Web Chat's MyGet feed:
https://github.com/microsoft/BotFramework-WebChat#how-to-test-with-web-chats-latest-bits
-->
<script src="https://cdn.botframework.com/botframework-webchat/latest/webchat.js"></script>
<style>
html,
body {
height: 100%;
}
body {
margin: 0;
}
#webchat {
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<div id="webchat" role="main"></div>
<script>
(async function () {
// In this demo, we are using Direct Line token from MockBot.
// Your client code must provide either a secret or a token to talk to your bot.
// Tokens are more secure. To learn about the differences between secrets and tokens
// and to understand the risks associated with using secrets, visit https://learn.microsoft.com/en-us/azure/bot-service/rest-api/bot-framework-rest-direct-line-3-0-authentication?view=azure-bot-service-4.0
// We are creating the Web Chat store here so we can dispatch WEB_CHAT/SEND_MESSAGE action later.
const store = window.WebChat.createStore();
window.WebChat.renderWebChat(
{
directLine: window.WebChat.createDirectLine({ token: '<your token>' }),
// We are passing our own version of Web Chat store.
store
},
document.getElementById('webchat')
);
document.querySelector('#webchat > *').focus();
// THIS IS THE IMPORTANT STUFF
const sendbox = document.querySelector("[aria-label='Sendbox']");
function removeQuestions() {
const questionDivs = document.querySelectorAll('.questions');
questionDivs.forEach((div) => {
div.remove();
})
}
// This ensures that we create unique listeners for each question
let totalQuestions = 0;
// Track the keypress events in the Send Box
sendbox.addEventListener('keypress', () => {
if (sendbox.defaultValue.length > 4) {
getQuestion();
} else {
removeQuestions();
}
});
// Send a message containing the innerText of the target element
function send(event) {
store.dispatch({
type: 'WEB_CHAT/SEND_MESSAGE',
payload: { text: event.currentTarget.innerText }
});
event.currentTarget.remove();
}
// This generates some test questions
function getQuestion() {
// Create questions div
const questions = document.createElement('DIV');
questions.setAttribute('class', 'questions');
document.querySelector('.content').appendChild(questions);
// Generate test questions
for (var i = 0; i < 4; i++) {
// Create question div
const question = document.createElement('DIV');
question.setAttribute('id', `question${totalQuestions}`);
question.setAttribute('class', 'probing');
question.innerText = `this is a test ${totalQuestions}`;
questions.appendChild(question);
// Create listener for question
const element = document.querySelector(`#question${totalQuestions}`);
element.addEventListener('click', send, false);
totalQuestions++;
}
}
})().catch(err => console.error(err));
</script>
</body>
</html>
There are likely more elegant ways to do this, but I wanted to get an answer out to you ASAP.
Note: I used vanilla javascript over jQuery to cut down on page load times and because I'm more familiar with it.
I am learning vue.js for the first time tonight and I can't wrap my head around why when I set a "list" array in the data function, i cannot change it in a method below. I have the following code and my template still spits out my original {name: 'daniel'}, {name: 'lorie'} variable.
My http call is definitely being made as i can see an array of like 100 users in the network tab, but "this.list = data" is not resetting my data variable
<template>
<pre>{{list}}</pre>
</template>
<script>
export default {
data () {
return {
list: [{name: 'daniel'}, {name: 'lorie'}]
}
},
created () {
this.fetchContactList()
},
methods: {
fetchContactList () {
this.$http.get('https://jsonplaceholder.typicode.com/users', (data) => {
this.list = data
})
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style lang="scss">
ul.user-list {
background: #fafafa;
border:1px solid #ebebeb;
padding:40px;
li {
list-style: none;
display: block;
margin-bottom:10px;
padding-bottom:10px;
border-bottom:1px solid #ebebeb;
}
}
</style>
You are attempting to pass your success callback in the options argument. The $http service uses promises with the following format:
this.$http.get('/someUrl', [options]).then(successCallback, errorCallback);
Change your get request to this:
this.$http.get('https://jsonplaceholder.typicode.com/users').then( (response) => {
this.list = response.body; // The data you want is in the body
});
this code works just fine, but the second input field does not show images appearing with the text suggestions. I would appreciate if someone could take a look and let me know what needs to be changed in the js for it to work.
Example queries: clinton, bush
you can see the script here http://predcast.com/include/autoc/jqui/test2.php
<!DOCTYPE html>
<html>
<head>
<title>jQuery UI Autocomplete: Custom HTML in Dropdown</title>
<link href="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/themes/smoothness/jquery-ui.min.css" rel="stylesheet">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"> </script>
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/jquery-ui.min.js"></script>
<style>
.loading {
display: none;
width: 16px;
height: 16px;
background-image: url(/img/loading.gif);
vertical-align: text-bottom;
}
#autocomplete.ui-autocomplete-loading ~ .loading {
display: inline-block;
}
.ui-menu-item {
padding:1px;
margin:1px;
}
.ac-m {
height:block;
overflow:auto;
padding:2px 2px 2px 2px;
}
.ac-img {
max-width:30px;
float:left;
margin:2px 2px 2px 2px;
}
.ac-title {
margin:1px;
font-size:14px;
}
.ui-autocomplete {
margin:1px;
}
</style>
</head>
<body>
<form action="http://www.test.com/">
<input class="autocomplete" type="text" placeholder="Option 1" name="e1">
<input class="autocomplete" type="text" placeholder="Option 2" name="e2">
<span class="loading"></span>
</form>
<script>
/*
* jQuery UI Autocomplete: Custom HTML in Dropdown
* http://salman-w.blogspot.com/2013/12/jquery-ui-autocomplete-examples.html
*/
$(function () {
$('.autocomplete').autocomplete({
delay: 500,
minLength: 3,
source: function (request, response) {
$.getJSON("http://predcast.com/include/autoc/jqui/jsond.php", {
q: request.term,
}, function (data) {
var array = data.error ? [] : $.map(data.movies, function (m) {
return {
label: m.title,
year: m.year,
img: m.img,
};
});
response(array);
});
},
focus: function (event, ui) {
event.preventDefault();
},
}).data("ui-autocomplete")._renderItem = function (ul, item) {
var $a = $("<div class='ac-m'></div>");
if (item.img) {
$("<span></span>").addClass(item.icon).appendTo($a).append("<img src='" + item.img + "' border='0' class='ac-img' />");
}
$("<span class='ac-title'></span>").text(item.label).appendTo($a);
return $("<li></li>").append($a).appendTo(ul);
};
});
</script>
</body>
</html>
The problem is related to the way you are defining the _renderItem extension point.
In your code, you are redefining the jquery-ui autocomplete _renderItem function only for your first widget instance, so the _renderItem for your second autocomplete instance is the default one defined in the jquery-ui code.
You are initializating the autocomplete for your 2 inputs with this $('.autocomplete').autocomplete({ ...}) then you get the first widget instance with this instruction .data("ui-autocomplete") and then redefine the _renderItem function for this instance only.
You can define it for all your instances like this:
// Create your widget instances
$('.autocomplete').autocomplete({
delay: 500,
minLength: 3,
source: function (request, response) {
$.getJSON("http://predcast.com/include/autoc/jqui/jsond.php", {
q: request.term,
}, function (data) {
var array = data.error ? [] : $.map(data.movies, function (m) {
return {
label: m.title,
year: m.year,
img: m.img,
};
});
response(array);
});
},
focus: function (event, ui) {
event.preventDefault();
}
});
// Then redefine the _renderItem for each instance
$('.autocomplete').each(function() {
$(this).data('ui-autocomplete')._renderItem = function (ul, item) {
var $a = $("<div class='ac-m'></div>");
if (item.img) {
$("<span></span>").addClass(item.icon).appendTo($a).append("<img src='" + item.img + "' border='0' class='ac-img' />");
}
$("<span class='ac-title'></span>").text(item.label).appendTo($a);
return $("<li></li>").append($a).appendTo(ul);
};
});
I am working on a project using Syncfusion Javascript gauge control to display a weekly pay bonus. The data is stored on a SharePoint list. I wrote a javascript to convert the sharepoint list from XML to JSON.
<script type="text/javascript">
$ajax({
url: "/_api/web/lists/GetByTitle('bonusEntry')/items?$orderby=Date desc&$filter=Department eq 'Meltshop'&$top=1",
type: "GET",
headers: {
"accept":"application/json;odata=verbose",
},
success: function (data) {
var newMsBonus = "";
for(i=0; i < data.d.results.length; i++){
newMsBonus = newMsBonus + "<div>" + data.d.results[i].ACrew + "</div>";
}
$('#oDataanalysisScoreBoard').html(newMsBonus);
},
error: function (error) {
alert("error: " + JSON.stringify(error));
}
})
Then the value is placed in this Div.
<div id="oDataanalysisScoreBoard"></div>
Basically what I would like to do is bind the data to the Syncfusion control which is set up like this:
$("#CircularGauge1").ejCircularGauge({
width: 500,
height: 500,
backgroundColor: "#3D3F3D",
readOnly: false,
scales: [{
ticks: [{
type: "major",
distanceFromScale: 70,
height: 20,
width: 3,
color: "#ffffff"
}, {
type: "minor",
height: 12,
width: 1,
distanceFromScale: 70,
color: "#ffffff"
}],
}]
});
Then the gauge is created inside this:
<div id="CircularGauge1"></div>
The gauge will build but I cannot get the gauge to recieve the value.
If anyone has any ideas on how I can make this work or things I'm doing I would greatly appreciate any input! Thanks everyone!
EDIT:
The synfusion software creates a gauge and changes the needle based on a number value thats given to it. My ajax call pulls a number entered into a Sharepoint list and then displays that in a div.
In the above code snippet you mentioned the passing value as “String”. If you pass the string value to the loop it will concatenate as string value only. But we need to pass the integer value to the Circular Gauge properties(width, height, distancefromscale) to take effect. Hence, change the code snippet with the following.
$.ajax({
url: "/Gauge/GetData",
type: "POST",
success: function (data) {
var newMsBonus = 0;
for (i = 0; i < data.length; i++) {
newMsBonus = newMsBonus + data[i].MajorDistanceFromScale; // Here i have used the MajorScale distanceFromScale value for the demo
}
$('#oDataanalysisScoreBoard').html(newMsBonus);
},
failure: function (error) {
alert("no data available");
}
});
And we have prepared the sample to meet your requirement with the MVC application including the “.mdf” database. We have created the table called “GaugeData” and added the two record. And using the “$.ajax” called the action method “GetData” and received the “JSON” data from the controller. Refer the following code snippet.
View Page:
$.ajax({
url: "/Gauge/GetData",
type: "POST",
success: function (data) {},
failure: function (error) {
}
});
Controller Page:
public class GaugeController : Controller
{
GaugeDataDataContext db = new GaugeDataDataContext();
public JsonResult GetData()
{
IEnumerable data = db.GaugeDatas.Take(500);
return Json(data, JsonRequestBehavior.AllowGet);
}
}
And then assigned the calculated value to the gauge property. Here, I have used the “MajorDistanceFromScale” value read from the database record and assigned to the gauge properties. Refer the following coding snippet.
var distanceValue = parseInt($("#oDataanalysisScoreBoard")[0].innerHTML);
$("#CircularGauge1").ejCircularGauge({
width: 500,
height: 500,
backgroundColor: "#3D3F3D",
readOnly: false,
scales: [{
ticks: [{
type: "major",
distanceFromScale: distanceValue,
height: 20,
width: 3,
color: "#ffffff"
}, {
type: "minor",
height: 12,
width: 1,
distanceFromScale: 70,
color: "#ffffff"
}],
}]
});
And also please refer the below attached sample for more reference.
GaugeListSample
I am building a JavaScript file uploader based on XHR. (Ajax in fact as I use jQuery)
I use some HTML5 features as the Drag&Drop API, and - at the moment - the FileReader API.
I have some questions about the process, because there are some things I do not understand, theoretically.
I - voluntarily - choose to not use one of the existing and well designed plugins / standalone uploaders for some reasons :
I have some specific needs, by example to add a title and description (as in facebook) to the item
I would to implement it myself as a try for the HTML5 API's.
I've read a tutorial Upload Files with Ajax but I find strange to use the FileReader API to finally append the images to the FormData API.
More than it, I do not really would to have a form, I just drop the images in a drop-area, get the files content with the FileReader API then send it with an AJAX request to my server.
I am just interested to know if someone's got a better process idea, because at the moment :
I get the dropped file(s) and read it's content (asynchronously, but take some time...)
I send this content with an AJAX request to the server
I write the content to a physical file on the server (take again some time)
I don't see how that could be optimized / faster, but it is silly to see the time for a big picture, and I just don't want to imagine it for a video by example...
Is it possible by example to only send a reference of the file with Ajax, and manage the upload directly, instead that get the file content then wait that the user click on the send button to send it ?
By example, how does the facebook uploader work, they seems to solve the problem / use something to fix it ?
(If someone is interested to get it or to take a look, here are a small sample of what I have done at the moment)
/* HTML */
<div id='drop-area'>
<h3 class='placeholder'>Drop your files there!</h3>
</div>
/* CSS */
#drop-area {
position: relative;
width: 100%;
height: 400px;
border: 1px dashed grey;
border-radius: 10px;
}
#drop-area.drag-over {
border: 1px solid cyan;
}
#drop-area .placeholder {
position: absolute;
top: 50%;
left: 50%;
width: 235px;
height: 25px;
margin: -12px 0 0 -117px;
line-height: 25px;
text-transform: uppercase;
}
/* JavaScript - jQuery way */
// This code is NOT AT ALL full-browser compatible !!
$(document).ready(function () {
var i,
$dropArea = $('drop-area'),
fileReader,
file,
result,
sendRequest = function () {
$.ajax({
url: 'upload.php',
type: 'post',
data: {
title: $('#title').val(),
description: $('#description').val(),
data: result, // base64 encoded data
type: file.type
},
processData: false, // No query string
contentType: false // No data formatting
}).fail(function (error, status) {
console.log(error, status);
alert('Fail...');
}).done(function (response, output) {
console.log(response, output);
alert('Uploaded!');
}).always(function () {
$('#file-form-container').empty().detach();
});
},
onFileFormSubmit = function (e) {
e.preventDefault();
sendRequest();
return false;
},
displayForm = function (data) {
$('body').append($('<div/>', {
'id': 'file-form-container'
}).append($('<form/>', {
'action': '#',
'id': 'file-form'
}).append($('<img/>', {
'src': data,
'alt': 'File',
'width': 100px
})).append($('<input/>', {
'id': 'title',
'type': 'text',
'name': 'title'
})).append($('<textarea/>', {
'id': 'description',
'class': 'description',
'name': 'description'
})).append($('<input/>', {
'type': 'submit',
'name': 'submit',
'value': 'Send!'
}))));
},
onProgress = function (e) {
console.log('progress', e);
// Update a <progress> element...
},
onLoadEnd = function (e) {
console.log('load end', e);
result = e.target.result;
displayForm(result);
},
onError = function (e) {
console.log('error', e);
// Display a message...
}
readFile = function (file) {
fileReader = new FileReader();
fileReader.onprogress = onProgress;
fileReader.onerror = onError;
fileReader.onloadend = onLoadEnd;
fileReader.readAsDataURL(file);
};
$dropArea.on('dragenter', function (e) {
$(this).addClass('drag-over');
}).on('dragover', function (e) {
e.preventDefault();
e.originalEvent.dataTransfer.dropEffect = 'copy'; // Check the browser support if you want to fix the compatibility
}).on('dragleave', function (e) {
e.preventDefault();
$(this).removeClass('drag-over');
}).on('dragend', function (e) {
e.preventDefault();
$(this).removeClass('drag-over');
}).on('drop', function (e) {
// e || e.originalEvent ?
e.preventDefault();
e.stopPropagation();
$(this).removeClass('drag-over');
if (e.originalEvent.dataTransfer.files) {
for (i = 0, i < e.originalEvent.dataTransfer.files.length; i++) {
// Work with arrays to manage multiple files
file = e.originalEvent.dataTransfer.files[i];
readFile(file); // Read the file content then process the upload (callbacks)
}
}
})
});
/* PHP - Symfony2 */
<?php
// Symfony 2 Controller Context
$em = $this->getDoctrine()->getEntityManager();
// get params
$request = $this->getRequest();
// Check for types, sizes, errors etc.
if ($request->get('data') && [...]) {
[...]
}
// write the decoded data into a file
// fwrite(base64_decode(...));
// By the way, is there any OOP - MVC way to do that with Symfony2 ?
$path = ''; // define the file path
// Save the entity
$entity = new Picture();
$entity->setTitle($request->get('title'));
$entity->setDescription($request->get('description'));
$entity->setPath($path);
$em->persist($entity);
$em->flush();
return new JsonResponse(array($entity), 202);
?>