I am using SignalR for Chat in my app. When a user connects, I use .append to add the users name to a div with a list of users. The code works fine in Chrome and Edge, but when I run it in FireFox the append does not work unless I hit F12 and run the code in debug mode.
Here is my javascript:
$(document).ready(function () {
initLoad = true;
loadRequests();
#Html.Raw(tabstr)
// Declare a proxy to reference the hub.
var chatHub = $.connection.chatHub;
$.connection.hub.start().done(function () {
registerEvents(chatHub)
});
registerClientMethods(chatHub);
});
function registerClientMethods(chatHub) {
chatHub.client.onNewUserConnected = function (connectionId, name, jobtitle) {
AddUser(chatHub, connectionId, name, jobtitle);
}
}
function AddUser(chatHub, connectionId, name, jobtitle) {
var userId = $('#hdId').val();
const connectionID = connectionId;
const userName = name;
const jobTitle = jobtitle;
const connectedUser = $("#divusers").append('<div id="' + connectionID + '" class="kt-widget__item" style="cursor:pointer"><div class="kt-widget__info"><div class="kt-widget__section"><a class="kt-widget__username">' + userName + '</a><span class="kt-badge kt-badge--success kt-badge--dot"></span></div>' + jobTitle + '</div></div>');
connectedUser.on("click", function () {
var groupWindows = [];
$('#groupWindowList').empty();
$('div[id^="ctr"]').each(function () { groupWindows.push(this.id); })
$.each(groupWindows, function (index, value) {
var controlname = value;
const groupName = controlname.replace("ctr", "")
const listItem = $(`<li>${groupName}</li>`);
listItem.on("click", function () {
$('#addToGroupModal').modal('toggle');
chatHub.server.addUserToGroup(groupName, connectionID);
});
$('#groupWindowList').append(listItem);
})
$('#addToGroupModal').modal({});
});
}
const connectedUser + $("#divusers").append is the problem. In debug, it is fine, but if I just run the code, the append does not take place and user's name does not display in the list.
Here is my html:
<div class="kt-portlet__body">
<div class="kt-widget kt-widget--users kt-mt-20">
<div class="kt-scroll kt-scroll--pull">
<div id="divusers" class="kt-widget__items">
</div>
</div>
</div>
</div>
UPDATE
So I added:
var myElement = $('#divusers')[0];
var observer = new MutationObserver(function(mutations) {
if (document.contains(myElement)) {
alert('hi');
});
observer.observe(document, {attributes: false, childList: true, characterData: false, subtree:true});
to check if the element exists in the DOM. I replaced the alert('hi') with the code to start the ChatHub and the append still does not work.
Another weird thing is if I make almost ANY change in the html and run it. It works the first time, but if I stop it and run it again. It doesn't work.
Any assistance is greatly appreciated.
Related
I currently have a page that has content that expands when you click on a term, but as soon as you click on a new term the old one closes and the new one expands. The terms are loaded in from a google sheet onto the page. This is on a HTML page but the javascript code to do the work is the following:
// Address of the Google Sheets Database
var public_spreadsheet_url = 'sheet link here';
// Column Names from Google Sheets Database
let questionsColumn = "Question";
let answersColumn = "Answer";
window.addEventListener('DOMContentLoaded', init) // Calls method init when Sheets has loaded
function init() {
Tabletop.init( { key: public_spreadsheet_url,
callback: showInfo,
simpleSheet: true } );
}
var unhiddenAnswer = "";
// Method that gets called when data has been pulled from Google Sheets
function showInfo(data) {
var editButton = '<center><a style="border-bottom: none" href="' + public_spreadsheet_url + '"><button class="button admin">Edit</button></a></center>';
// Injects the built HTML code into the div Dynamic
document.getElementById("dynamic").innerHTML = buildFAQTable(data) + editButton;
}
// Builds the HTML Table code from the Database Data
function buildFAQTable(data) {
var index = 0;
var content = '<h2>Title Here</h2><div style="padding:0px 5%">';
data.forEach(form => {
content += '<h1 class="faq_question" onClick="unhideAnswer(' + index + ')">' + data[index][questionsColumn] + '</h1>';
content += '<p id="answer' + index + '" class="hideAnswer">' + data[index][answersColumn] + '</p>';
index++;
});
// Extends body to accomdate for tall footer on very small devices (e.g. iPhone 5/5S/SE)
content += "<br></br><br></br>";
return content;
}
// When a FAQ Question gets clicked on, this method will hide the currently displaying answer (if any), and
// Unhide the answer corresponding to the clicked on answer.
// If the currently displaying answer is the same as the answer corresponding to the clicked on question,
// it will be hidden and no new answer will be unhidden
function unhideAnswer(number) {
var answerID = "answer" + number;
if (answerID != unhiddenAnswer) {
document.getElementById(answerID).classList.remove("hideAnswer");
}
if (unhiddenAnswer != "")
document.getElementById(unhiddenAnswer).classList.add("hideAnswer");
if (unhiddenAnswer == answerID)
unhiddenAnswer = ""
else
unhiddenAnswer = answerID;
}
I want to now add an expand all/ collapse all button to give the user the option to open and view all the terms at one if needed. However, if not using the expand all button, the regular open and close functionality above should be used. I am new to javascript and am at a loss on the best way to implement this. Any help would be appreciated.
add a answer class to every answer, then you can loop through all of them with this query selector
// in your buildFAQTable fucntion
content += '<p id="answer' + index + '" class="hideAnswer answer">' + data[index][answersColumn] + '</p>';
document.querySelectorAll('.answer').forEach(answer => {
// you can use toggle, add or remove to change the appearance of the answer
answer.classList.toggle('hideAnswer')
})
i would also recomend you to check out some of the newer javascript features like string interpolation and avoid using var, but it is not so important if you are just starting out.
(i also refactored some of your code, this might make it a bit more readable)
// Address of the Google Sheets Database
const public_spreadsheet_url = 'sheet link here';
// Column Names from Google Sheets Database
const questionsColumn = "Question";
const answersColumn = "Answer";
function toggleAnswer(num) {
const answer = document.getElementById(`answer${num}`);
answer.classList.toggle('hideAnswer');
}
function hideAll() {
document.querySelectorAll('answer').forEach(answer => {
answer.classList.add('hideAnswer');
})
}
function showAll() {
document.querySelectorAll('answer').forEach(answer => {
answer.classList.remove('hideAnswer');
})
}
function buildFAQTable(data) {
let index = 0;
let content = '<h2>Title Here</h2><div style="padding:0px 5%">';
for (i in data) {
content += `<h1 class="faq_question" onClick="unhideAnswer(${i})">${data[i][questionsColumn]}</h1>`;
content += `<p id="answer${i}" class="hideAnswer answer">${data[i][answersColumn]}</p>`;
}
content += "<br></br><br></br>";
return content;
}
function showInfo(data) {
const editButton = `<center><a style="border-bottom: none" href="${public_spreadsheet_url}"><button class="button admin">Edit</button></a></center>`;
document.getElementById("dynamic").innerHTML = buildFAQTable(data) + editButton;
}
window.addEventListener('DOMContentLoaded', () => {
Tabletop.init({
key: public_spreadsheet_url,
callback: showInfo,
simpleSheet: true
});
}, { once: true })
I am trying to add a JS script file called chatfunction.js into my index.html in Blazor but it gives me an error that it cannot find a file. My CSS is linked correctly and the HTML and CSS both show up but it does not provide any of the JS functionality that I have implemented.
I am adding it at the bottom of my HTML in index.html like this:
....
<script src="_framework/blazor.webassembly.js"></script>
<script src="chatfunction.js"></script>
</body>
</html>
Here is my project structure
Now when I try compiling it gives me this error:
(JS) File 'C:/Users/darka/source/repos/chatproject/wwwroot/js/mysrc.js' not found.
I don't get why it can't find it and I am confused as to why it thinks my file is mysrc.js as there is no file like that in my project structure.
Any pointers how to fix this?
Here is the layout of my JS file
var botController = (function () {
})();
var uiController = (function () {
})();
var controller = (function (botCntr, uiCntr) {
var $chatCircle,
$chatBox,
$chatBoxClose,
$chatBoxWelcome,
$chatWraper,
$submitBtn,
$chatInput,
$msg;
/*toggle*/
function hideCircle(evt) {
evt.preventDefault();
$chatCircle.hide('scale');
$chatBox.show('scale');
$chatBoxWelcome.show('scale');
}
function chatBoxCl(evt) {
evt.preventDefault();
$chatCircle.show('scale');
$chatBox.hide('scale');
$chatBoxWelcome.hide('scale');
$chatWraper.hide('scale');
}
function chatOpenMessage(evt) {
evt.preventDefault();
$chatBoxWelcome.hide();
$chatWraper.show();
}
//generate messages on submit click
function submitMsg(evt) {
evt.preventDefault();
//1. get input message data
msg = $chatSubmitBtn.val();
//2.if there is no string button send shoudn't work
if (msg.trim() == '') {
return false;
}
//3. add message to bot controller
callbot(msg);
//4. display message to ui controller
generate_message(msg, 'self');
}
function chatSbmBtn(evt) {
if (evt.keyCode === 13 || evt.which === 13) {
console.log("btn pushed");
}
}
/* var input = uiCntr.getInput();*/
/* $chatSubmitBtn.on("click", hideCircle);*/
function init() {
$chatCircle = $("#chat-circle");
$chatBox = $(".chat-box");
$chatBoxClose = $(".chat-box-toggle");
$chatBoxWelcome = $(".chat-box-welcome__header");
$chatWraper = $("#chat-box__wraper");
$chatInput = $("#chat-input__text");
$submitBtn = $("#chat-submit");
//1. call toggle
$chatCircle.on("click", hideCircle);
$chatBoxClose.on("click", chatBoxCl);
$chatInput.on("click", chatOpenMessage);
//2. call wait message from CRM-human
$submitBtn.on("click", chatSbmBtn);
$chatInput.on("keypress", chatSbmBtn);
//6. get message from bot controller-back end
//7. display bot message to ui controller
}
return {
init: init
};
})(botController, uiController);
$('.chat-input__form').on('submit', function (e) {
e.preventDefault();
msg = $('.chat-input__text').val();
$('.chat-logs').append('<div id="cm-msg-0" class="chat-msg background-warning push-right bot"><div class="cm-msg-text">' + msg + '</div><span class="msg-avatar"><img class="chat-box-overlay_robot" src="https://www.meetsource.com//userStyles/images/user.png"></span></div>');
$('.chat-input__text').val('');
});
$(document).ready(controller.init);
function talk() {
var user = document.getElementById("userBox").value;
document.getElementById("userBox").value = "";
document.getElementById("chatLog").innerHTML += user + "<br>";
}
I think your script line needs to be:
<script src="js/chatfunction.js"></script>
I've made a script based on : update properties of geojson to use it with leaflet
>>>Working script picture
But I have an issue with multiple arguments.. I'd like to put 2 separate variables like:
layer.feature.properties.desc = content.value;
layer.feature.properties.number = content2.value;
But
layer.bindPopup(content).openPopup()
can open only one - "content", there is an error when I put for example:
layer.bindPopup(content + content2).openPopup();
>>> Picture
So I made another script:
function addPopup(layer)
{let popupContent =
'<form>' +
'Description:<br><input type="text" id="input_desc"><br>' +
'Name:<br><input type="text" id="input_cena"><br>' +
'</form>';
layer.bindPopup(popupContent).openPopup();
document.addEventListener("keyup", function() {
link = document.getElementById("input_desc").value;
cena = document.getElementById("input_cena").value;
layer.feature.properties.link = link;
layer.feature.properties.cena = cena;
});
};
>>>Picture
But unfortunately:
layer.feature.properties.link = link;
layer.feature.properties.cena = cena;
Is the same for each drawn geometry. Moreover when user fill the form, the arguments will dissaper just after close PopUp.. With update properties of geojson to use it with leaflet script inscribed argument is visible each time when user "click" on PupUp
Can any one help me on this?
You have to add the listener in the popupopen event.
Change your addPopup function to:
var openLayer;
function addPopup(layer){
let popupContent =
'<form>' +
'Description:<br><input type="text" id="input_desc"><br>' +
'Name:<br><input type="text" id="input_cena"><br>' +
'</form>';
layer.bindPopup(popupContent).openPopup();
layer.on("popupopen", function (e) {
var _layer = e.popup._source;
if(!_layer.feature){
_layer.feature = {
properties: {}
};
}
document.getElementById("input_desc").value = _layer.feature.properties.link || "";
document.getElementById("input_cena").value = _layer.feature.properties.cena || "";
document.getElementById("input_desc").focus();
openLayer = _layer;
});
layer.on("popupclose", function (e) {
openLayer = undefined;
})
};
L.DomEvent.on(document,"keyup",function(){
if(openLayer){
link = document.getElementById("input_desc").value;
cena = document.getElementById("input_cena").value;
openLayer.feature.properties.link = link;
openLayer.feature.properties.cena = cena;
}
})
https://jsfiddle.net/falkedesign/ntvzx7cs/
I wrote an custom API(node.js app) that gets the info about the blogs from medium.com, right now there is
the author/main pic of the article,
title,
link to the article on medium.com(redundant),
the entire article text, in the JSON output.
Sample API/JSON:
{
"img": [
"https://upload.wikimedia.org/wikipedia/commons/4/42/Blog_%281%29.jpg"
],
"title": [
"The old and the new or not so new: Java vs JavaScript"
],
"link": [
"https://medium.com/#aki9154/the-old-and-the-new-or-not-so-new-java-vs-javascript-760f84e87610?source=rss-887f1b1ddb75------2"
],
"desc": [
"<p>It’s funny how the name JavaScript makes you believe that it is somehow..."
]
}
Then i am polling this API/JSON and spitting out the output in a thumbnail format, basic html for now(no design/CSS).
Where i am stuck is when a user clicks on a thumbnail and i need to make sure that i display the correct article?!
For which i need to display a new page when the thumbnail/article is clicked, i can use #4 from JSON above as an output for that dynamically created new page and put it out nicely)
The issue that i am facing now is how to dynamically produce the correct article when the dynamically created link is clicked?
Right now nothing happens when i click on the thumbnail and that's what this project link displays...
I did some stackoverflow research and read some jQuery docs(event propagation and more...) and was able to make changes to the index.js, below is how it looks like but nothing works, any help will be appreciated...
index.js:
$(function () {
var desc = "";
function newWin() {
var w = window.open();
$(w.document.body).html('<p>'+desc+'</p>');
}
var $content = $('.cards-in-grid');
var url = 'link-for private use now';
$.get(url, function (response) {
var output = '';
console.log(response);
$.each(response, function (k, item) {
title = item.title;
var author = item.img;
desc = item.desc;
output += '<li><img src="'+author+'" alt=""><h2>' + title + '</h2></li>';
$(".cards-in-grid ul").on("click", "li", function(){
newWin;
});
return k;
});
$content.html(output);
});
});
`
$(function () {
var $content = $('.cards-in-grid');
var url = 'link-for private use now';
$.get(url, function (response) {
var output = '';
var list = "li";
$.each(response, function (k, item) {
var listNum = list+k;
var idy = "#"+listNum;
var desc = "";
title = item.title;
var author = item.img;
desc = item.desc;
//GIVE ID to each LI using a variable
output += '<li id="'+listNum+'"><img src="'+author+'" alt=""><h2>' +
title + '</h2></li>';
$content.html(output);
$content.on("click",idy, function(){
var w = window.open();
$(w.document.body).html('<p>'+desc+'</p>');
});
return k;
});
});
});
This worked perfectly, some thinking and pondering and was able to make it work!!
Kindly Upvote the answer, if it helped you! Thanks!
I am instantiating a new variable from a class. The class has one constructor, city and then fetches jazz clubs through the foursquare API.
When I hard-code the city name into the instantiated class, it works fine. But when I want to feed it a dynamic value (a query from the search bar which I grab through the DOM), it won't recognise the city. Here is the code:
The Class:
class Venues {
constructor(city) {
this.id = '...';
this.secret = '...';
this.city = city;
}
async getVenues() {
const response = await fetch(`https://api.foursquare.com/v2/venues/search?near=${this.city}&categoryId=4bf58dd8d48988d1e7931735&client_id=${this.id}&client_secret=${this.secret}&v=20190309`);
const venues = await response.json();
return venues;
}
}
const input = document.getElementById('search-input').value;
const button = document.getElementById('button');
const jazzClubs = new Venues(input);
button.addEventListener('click', (e) => {
e.preventDefault();
getJazzVenues();
})
function getJazzVenues() {
jazzClubs.getVenues()
.then(venues => {
console.log(venues);
})
.catch(err => {
console.log(err);
});
}
Anyone knows why the the input variable's value is not recognised by the newly instantiated jazzClubs variable?
Also, if you have tips on how to structure this code better or neater, I'd welcome any suggestions (the class definition is in a separate file already).
Many thanks guys!
Adam
You need to make sure, the following statements are triggered after the button click.
const input = document.getElementById('search-input').value;
const jazzClubs = new Venues(input);
Also your code looks too complex. Use simpler code using jquery.
Try something like this:
$(document).ready(function() {
$("#search-button").click(function() {
var searchval = $("#search-input").val();
var id = "xxx";
var secret = "yyy";
alert(searchval);
var url = "https://api.foursquare.com/v2/venues/search?near=" + searchval + "&categoryId=4bf58dd8d48988d1e7931735&client_id=" + id + "&client_secret=" + secret + "&v=20190309";
alert(url);
$.ajax({
url: url,
dataType: 'json',
success: function(data) {
var venues = data.response.venues;
alert(venues);
$.each(venues, function(i, venue) {
$('#venue-result').append(venue.name + '<br />');
});
}
});
});
});
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<label>City:</label>
<input type="text" id="search-input" />
<button type="button" id="search-button">Search</button>
<div id="venue-result"></div>
</body>
</html>