pusher and rails updating a div - javascript

When a push is recieved I want it to update a div.
I don't understand javascript that well, but this is what i've got so far.
#subscription
var pusher = new Pusher('<%= Pusher.key %>');
var channel = pusher.subscribe('test_channel');
channel.bind('greet', function(data) {
$("#data.greeting").load(location.href + " #data.greeting");
});
#trigger
<%= Pusher['test_channel'].trigger('greet', { :greeting => "present"}) %>
#present is the div im trying to update in this example. the trigger works, but nothing happens on the sub end

Are you rendering the trigger in the view, as in, in your .erb file?
Trying keeping the subscription code the same and then running the trigger code in your rails console, as in, just this bit:
Pusher['test_channel'].trigger('greet', { :greeting => "present"})

I solved it like this.
channel.bind('greet', function(data) {
$("#present").load(location.href + " #present");
});
it just ignores the input from the trigger and runs that commands, works well. might be a little more work implementing in this way, but it will do.

Related

Reading data from firebase everytime button is clicked, without having to refresh

I am quite the beginner in programming with web applications. My goal is to receive data from realtime firebase database.
So I have this code to read from realtime firebase application. When I do this I can actually see the output. My problem is that if I change a value in the input-box and submit again without reloading page, the javascript will not run the new input value.
For the console output in internet:
The problem is here, if I change value to "1" in input box without refreshing page, my program won't take that input and do stuff with it. Check below:
It's suppose to return a value of 0 and where i marked with circle it should say "1". If i refresh page and then put in 1 into input box, it works fine. But if I change back to 2 without refreshing. same problem.
I just want to do the same without user having to refresh page eveyrtime they type in new data.
Hope someone out there can help :) I watched so many tutorials for reading from database and I can't figure out what to do here.
You can use oninput JS event to capture a value when it is changed
var standNr = document.getElementById("standNr");
standNr.oninput = function() {
console.log(standNr.value);
}
<input type="text" id="standNr"/>
defineStand.addEventListener('submit', (e) => {
var stand_number = document.getElementById("standnr").value
var dbRef = database.ref('stand/' + stand_number + '/status')
e.preventDefault()
dbRef.on('value', function(snapshot) {
console.log(snapshot.val())
})
console.log(stand_number)
console.log(dbRef)
})
I solved it now. Works perfectly :D
My issue was that e.preventDefault wasn't placed after definings the variables :)

SessionStorage Navigation

Greets, so I I'm trying to learn jquery/javascript storage and ran into an issue where I am building a navigation that should remember and place you where you last were if you refresh the page (that's why i use sessionStorage rather then localStorage).
But I can't seem to change the sessionStorage variable to the new location, nor figure out a functional way to get the user back on refreshing the page.
This is what I currently have.
$(function() {
sessionStorage.setItem('position', '.first');
var location = sessionStorage.getItem('position');
$('li', this).click(function() {
cls = $(this).text();
if('.' + cls != location) {
$(location).slideToggle(400);
$('.' + cls).delay(400).slideToggle(400);
sessionStorage.setItem('position', '.' + cls)
console.log(location)
};
});
});
https://jsfiddle.net/Unkn0wn96/ndj9sqpe/
The code works in an very odd way, rather then how it's intended, including never changing the value when I console.log(location).
I made some further testing on this and found a 'more' working way in the was that the sessionStorage does change to something, yet it not being usefull.
https://jsfiddle.net/Unkn0wn96/nkbtykkr/
but yet, they elements don't toggle as they should, including that when I console log sessionStorage.position it returns NaN. Also for some odd reason I can't store sessionStorage.position within a variable, it just refuses to change its value. I have no clue why this is happening.
So I was finally able to solve my issue with sessionStorage, since there was not much of help I'd assume the information regarding the case was limited and so wish to share my solution. All thought it does not work fully as intended it does execute it's main function.
$(function() {
$('button').on('click', function() {
var msg = '.'+$(this).text();
localStorage.setItem('color', 'blue') //Default (does not matter since the if statement does not register)
if(msg != '.' + localStorage.color) { // DOES NOT REGISTER
if(localStorage.length > 0) {
localStorage.removeItem('color')
console.log('localStorage.length : ' + localStorage.length)
};
localStorage.setItem('color', msg)
console.log(localStorage.color)
} else {
console.log('cancelled')
}
});
});
https://jsfiddle.net/mdqjoz69/4/
So what I finally was able to achieve was to make a localStorage key change it's value regarding of what button you press.
What I failed to achieve was being able to check the stored data to not execute whenever you store something that have already been stored. There might be a work around for this. But since the code serves its main purpose I'll let it slide.

Rails ActionCable / Turbolinks chat issue: posting duplicate messages

I'm having an issue with an ActionCable and Turbolinks. I've set up a chat app similar to the example chat app shared by DHH.
In order to have multiple chat rooms and pass a chat room ID to the ActionCable subscription initializer, I have something like this:
$(document).on("turbolinks:load",function(){
var pod_slug = $("#pod_slug_value").val();
App.pods = App.cable.subscriptions.create(
{ channel: 'PodsChannel', pod_slug: pod_slug },
{
received: function(data) {
if ( $(".chat-stream").length ){
$(data.message).appendTo($(".chat-stream"));
$(".chat-stream").scrollTop($(".chat-stream")[0].scrollHeight);
}
},
speak: function(message, pod_slug) {
return this.perform('speak',{
message: message,
pod_slug: pod_slug
});
}
});
// captures text input from input field
captureMessage();
});
However, when I click around the app and come back to the page, Turbolinks seems to be binding the subscription handler multiple times and now when I submit a message, I get duplicate messages in the chat stream.
I've tried slicing this problems in every which way. I don't have the problem when I don't preface the subscription handler with:
$(document).on("turbolinks:load",function(){...
But then I am unable to get the chat room id (pod_slug), because the document DOM doesn't load before the javascript executes.
It seems like this problem would have a simple solution as both ActionCable and Turbolinks are heavily supported by Basecamp. Many of the demo chat tutorials suggest setting up chat in exactly this way. Am I missing something here?
I have had the same issue and fixed it in this way
if (!App.pods) {
App.pods = App.cable.subscriptions.create(
{ channel: 'PodsChannel', pod_slug: pod_slug },
{ ... /* and so on */ }
}
Every time you reload page, 'turbolinks:load' event works, so you have to check whether App.pods object has been already created.
Hope this will help you.
You can use App.cable.subscriptions.remove to remove a subscription returned by App.cable.subscriptions.create. So maybe check if App.pods is set, and if so remove it before you subscribe again.
I like your approach, MaruniakS. Digging into the consumer object, it looks like it has a test to see if it's disconnected. Changing just the first line, we could also do:
if (!App.pods || App.pods.consumer.connection.disconnected) {
App.pods = App.cable.subscriptions.create(
{ channel: 'PodsChannel', pod_slug: pod_slug },
{ ... /* and so on */ }
}

Switching views within a Marionette region

I have a region in my Marionette project called the "primary" region for which I show a loading view and then a download view once the loading (decrypting) is finished. Here's what I have it doing right now:
var loadingView = new fileView.Loading();
appManager.regions.primary.show(loadingView);
//Promise waiting for file to decrypt before
//switching views
decryptFile(file).then(function (decryptedFile) {
var downloadView = new fileView.Download({
model: decryptedFile
});
appManager.regions.primary.show(downloadView);
})
As of now, when the decrypt function is finished, my primary region goes blank instead of showing my downloadView. I've made sure downloadView exists and works fine by logging it to the console so that's not the problem. Any ideas why it isn't showing up?
Edit: Also, my downloadView does render just fine when I pull the code outside of the promise.
Found out what was going wrong! My model was invalid and was causing the view to not load. Unfortunately an error didn't show when this happened.

Running some code only once in AngularJS

I have some code that I need to run only once, but I'm not sure where do that code belongs to (service? factory?)
This is the code:
socket.on('recv chat', function (data){
$("#chat").append(
"<b><" + data.nick + "></b>: " +
data.texto +
"<br>"
);
});
As you can see from the code, it's just a basic chat-app. My whole webpage has a few tabs and one of those tabs is the chat-tab. If I put this code inside my chat's controller, it gets executed on each tab-switch, so when somebody sends a message, it gets appended a few times.
Where should I place it for it to be executed only once?
You say it should execute only once, but presumably what you actually want is just that it display the values. If so the obvious thing would be for the code to update the model and then use angular's data binding for the display. (A good rule of thumb in angular would be that anywhere except a directive that tries to manipulate the DOM is probably doing it wrong).
So, some untested code to put inside your controller might be:
socket.on('recv chat', function (data){
$scope.apply(function() {
$scope.nick = data.nick;
$scope.texto = data.texto;
});
});
And your html just has:
<div ng-show="nick"><b><{{nick}}></b>: {{texto}}</div>
I think you need to wrap the model updates in $scope.apply() otherwise the event won't be happening in the correct angular context.
Answer to your comment:
Is there a new socket within each new instance of the controller? If so there's no problem as the old event handler at worst updates the old model and should go away when the old socket goes away. If you're re-using the socket between controllers then I think you want to define a service to handle the socket and you can register the callback with the service.
var stopWatch = $scope.$on('someEvent', function(){
//some code here
stopWatch();
});
This is not the best solution but this is by far the best working solution i have came across. You need to remove the already registered even. Just add this line before you attach the events.
socket.removeAllListeners();
socket.on('recv chat', function (data){
$("#chat").append(
"<b><" + data.nick + "></b>: " +
data.texto +
"<br>"
);
});

Categories