how to use connect-flash with ajax - ajax

I have a page with a form that posts edits to a local endpoint via AJAX ($.post). I want to display a message to the user whether it went good or bad. But I can't get it to work. Here's what I have so far:
jade template (excerpt)
if message
.alert.alert-danger= message
// Tab panes
.tab-content
#admin-tab-profile.tab-pane.active(role='tabpanel')
h3 Profil
form
include partials/admin/profile
main.js (excerpt)
app.post('/admin', function(req, res) {
var data = req.body;
// find profile
profile.findById(data._id, function(err, profile) {
// update
profile.summary.da = data.da;
profile.summary.en = data.en;
// save
profile.save(function(err) {
if (err) {
req.flash('loginMessage', 'Oops! Something went wrong.');
res.status(500).send( { message: req.flash('loginMessage') } );
}
console.log("profile sucessfully updated");
req.flash('loginMessage', 'Yes! Everythings good!');
res.status(200).send( { message: req.flash('loginMessage') } );
});
});
});
app.js (excerpt)
app.use(flash()); // use connect-flash for flash messages stored in session
So what am I doing wrong? Why is not shown status messages when posting data?

Well if your using ajax you don't have to use express flash messages, you can simply use ajax.success method:
$.ajax({
method:'post',
url: '/user/singup',
data: data,
success: function(msg) {
console.log('Success!!');
console.log(msg); // loginMessage from your code
},
error: function() {
console.log('Error!!');
}
})
And send the status code from your post method in express:
res.status(200).send({ message: 'loginMessage' });

I managed to do that. I made it same as here:
https://www.npmjs.com/package/express-messages
<body>
<%- messages('my_message_template', locals) %>
<div id="messages">
<% Object.keys(messages).forEach(function (type) { %>
<% messages[type].forEach(function (message) { %>
<div class="alert alert-<%= type%>">
<%= message %>
</div>
<% }) %>
<% }) %>
</div>
And in $.ajax({ success:... I put this line:
$('#messages').load(location.href + " #messages");
So if ajax action was successful, it refreshed the div that id = messages.
In express I have this line:
res.status(200).json({ messages: req.flash('success','Yes! Everythings good')});
In above link, it states <%= type %> (ejs) if message is success or error (ie) and for that the styling is ie:
<style>
.alert-success{
color: #3c763d;
background-color: #dff0d8;
border-color: #d6e9c6;
}
.alert-error{
color: #a94442;
background-color: #f2dede;
border-color: #ebccd1;
}
</style>
This colors the background to green if message is 'success' or red if it's 'error'

Related

Rails 6 action cable chat app not working in firefox

I made a Rails 6 app and added a private messaging feature in it using action cable. The chat works fine in chrome and edge but crashes in firefox. Upon investigation in firefox, I think whenever the 'send' button in the create message form is clicked, it seems it reloads the page, disconnecting the current subscription. It says in the terminal that the async job is performed successfully before it gets disconnected. The data (in received(data)) doesn't get console logged in the browser.
I thought I just need to prevent the page to reload once the 'send' button is clicked so I tried placing preventDefault in submit listener in both application.js and conversation_channel.js but didn't work. Also added onclick: false in the submit tag in message form but didn't work also. It's maybe my theory is wrong or maybe I executed the solution wrong.
Please tell me if you need more snippets of my code:
// this is app/javascript/channels/conversation_channel.js
import consumer from "./consumer"
document.addEventListener('turbolinks:load', () => {
const conversation_element = document.getElementById('conversation-id');
const conversation_id = Number(conversation_element.getAttribute('data-conversation-id'));
const input_box = document.getElementById('message-input-box');
const send_button = document.getElementById('send-btn');
// for terminating other subscriptions when connected to a new subscription
consumer.subscriptions.subscriptions.forEach(subs => {
consumer.subscriptions.remove(subs);
});
consumer.subscriptions.create({ channel: "ConversationChannel", conversation_id: conversation_id }, {
connected() {
// Called when the subscription is ready for use on the server
console.log('Connected to conversation id: ' + conversation_id);
send_button.addEventListener('submit', function(e) { e.preventDefault(); });
},
disconnected() {
// Called when the subscription has been terminated by the server
},
received(data) {
// Called when there's incoming data on the websocket for this channel
console.log(data);
const el_user_id = document.getElementById('user-id');
const user_id = Number(el_user_id.getAttribute('data-user-id'));
let html;
user_id === data.message.user_id ? html = data.own_message : html = data.not_own_message;
const messageContainer = document.getElementById('messages-container');
messageContainer.innerHTML += html;
send_button.disabled = false;
input_box.value = '';
}
});
});
this is where the user creates a message: app/views/messages/_form.html.erb
<%= form_with scope: :message, url: item_conversation_messages_path(#conversation.item.id, #conversation.id), local: true, remote: true do |f| %>
<div class="form-inline">
<%= f.hidden_field :conversation_id, value: #conversation.id %>
<%= f.hidden_field :user_id, value: current_user.id %>
<%= f.text_field :content, placeholder: 'Type your message here...', class: 'form-control mr-2', id: 'message-input-box' %>
<%= f.submit 'Send', id: 'send-btn', class: 'btn btn-primary' %>
</div>
<% end %>
It was pointed out by user even_progression in my reddit post https://www.reddit.com/r/rails/comments/ol9ygj/rails_6_action_cable_chat_app_not_working_in/ that I should check the local and remote options in the message form. I set local to false and remote to true and now it works. Idk yet why but I'm about to find out.

How to pass parameters in axios url?

I am trying to use Axios in my Ruby Sinatra Project.
There is a url defined in my ruby file.
post '/follow/:id' do
# do something
end
In my erb file, I am trying to pass the variable in view to my inline script.
<body>
<div id="follow_element">
<button v-on:click="followUser">Follow</button>
</div>
<script>
window.addEventListener('load', function(){
const app = new Vue({
el: "#follow_element",
methods:{
followUser(){
axios.post("/follow", {
params: {
id: <%= #user.id %>
}
})
}
}
})
})
</script>
</body>
What I want is if the user click the button, the app would hit the /follow/:id url to update result. However, I met two problems.
First, the <%= #user.id %> doesn't work (#user is a variable available in this erb). The second is the app hits the '/follow' endpoint, instead of '/follow/:id' endpoint.
Could you please give me some suggestions? Thanks very much.
Note that as you wrote this:
post '/follow/:id' do
# do something
end
You'll now accept POST requests like: /follow/oneRandomId, follow/124184965 and so on...
Right here, you are making a request to /follow, passing POST params that is not in url. This will not work:
axios.post("/follow", {
params: {
id: <%= #user.id %>
}
})
In order to fix it, you can generate an URL with the available #user.id and make the POST request, like this:
axios.post("/follow/<%= #user.id %>")
Or, if you want to pass some data to the user (POST data, not URL params), you can do this:
axios.post("/follow/<%= #user.id %>", {
name: 'A beautiful name to insert to an user with that ID'
})
If you're still getting stuck, you can also use axios(config), that I think a bit clearer about what it is doing, from axios README page:
axios({
method: 'post',
url: "/follow/<%= #user.id %>",
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
});

Dropzone and another input type file?

<input type="file" name="default_image" id="imgInp" value="{{$property->default_image}}">
<div class="dropzone_upload">
<div class="dz-message" data-dz-message>
<span>
<img src='/assets/home/img/cloud_upload.png'/><br/>DRAG AND DROP IMAGES HERE <br/> <span class='or'>or</span> <br/> <a href='javascript:void(0)' class='upload_images'>UPLOAD IMAGES</a>
</span>
</div>
</div>
Now i have a problem when i upload default image and images in dropzone it mix those two so everything puts in default_image[].
Any suggestion how can i fix that?
When i do like this it say that image must be a type of jpeg,bmp,png:
$this->validate($request,[
'default_image' => 'mimes:jpeg,bmp,png|max:2000'
]);
This is my config for dropzone:
Dropzone.options.myDropzone = { // The camelized version of the ID of the form element
// The configuration we've talked about above
addRemoveLinks: true,
previewsContainer: '.dropzone-previews',
autoProcessQueue: false,
uploadMultiple: true,
parallelUploads: 10,
maxFiles: 10,
autoDiscover:false,
paramName:'gallery_images',
// The setting up of the dropzone
init: function() {
var myDropzone = this;
// First change the button to actually tell Dropzone to process the queue.
this.element.querySelector("button[type=submit]").addEventListener("click", function(e) {
// Make sure that the form isn't actually being sent.
if (myDropzone.getQueuedFiles().length > 0) {
e.preventDefault();
e.stopPropagation();
myDropzone.processQueue();
}
});
// Listen to the sendingmultiple event. In this case, it's the sendingmultiple event instead
// of the sending event because uploadMultiple is set to true.
this.on("sendingmultiple", function() {
console.log('sendingmultiple');
// Gets triggered when the form is actually being sent.
// Hide the success button or the complete form.
});
this.on("successmultiple", function(files, response) {
console.log('successmultiple error',response);
// Gets triggered when the files have successfully been sent.
// Redirect user or notify of success.
$("html, body").animate({ scrollTop: 0 }, "slow");
$("#resultMsg").css('display', 'block').text(response.successMsg);
});
this.on("errormultiple", function(files, response) {
console.log('response error',response);
// Gets triggered when there was an error sending the files.
// Maybe show form again, and notify user of error
});
}
};
You need to use the rule like this:
$this->validate($request,[
'default_image.*' => 'mimes:jpeg,bmp,png|max:2000'
]);
For more details: https://laravel.com/docs/5.4/validation#validating-arrays

How to display error message of jquery dropzone

I use dropzone with CI, i don't know how to display error message and custom message when upload false, this is my script
Dropzone.autoDiscover = false;
try {
var myDropzone = new Dropzone("#adminform" , {
paramName: "filename", // The name that will be used to transfer the file
maxFilesize: 0.5, // MB
url: window.location.href,
addRemoveLinks : true,
dictDefaultMessage :
'<span class="bigger-150 bolder"><i class="ace-icon fa fa-caret-right red"></i> Drop files</span> to upload \
<span class="smaller-80 grey">(or click)</span> <br /> \
<i class="upload-icon ace-icon fa fa-cloud-upload blue fa-3x"></i>',
dictResponseError: 'Error while uploading file!',
//change the previewTemplate to use Bootstrap progress bars
previewTemplate: "<div class=\"dz-preview dz-file-preview\">\n <div class=\"dz-details\">\n <div class=\"dz-filename\"><span data-dz-name></span></div>\n <div class=\"dz-size\" data-dz-size></div>\n <img data-dz-thumbnail />\n </div>\n <div class=\"progress progress-small progress-striped active\"><div class=\"progress-bar progress-bar-success\" data-dz-uploadprogress></div></div>\n <div class=\"dz-success-mark\"><span></span></div>\n <div class=\"dz-error-mark\"><span></span></div>\n <div class=\"dz-error-message\"><span data-dz-errormessage></span></div>\n</div>",
});
}
catch(e) {
alert('Dropzone does not support older browsers!');
}
And PHP return 400:
$this->output->set_header("HTTP/1.0 400 Bad Request");
But when i hover image it's display [object Object] but message is:
dictResponseError: 'Error while uploading file!'
For anyone in need:
You can return a response message from the server using echo. Then in the js code add an error event handler
PHP
header("HTTP/1.0 400 Bad Request");
echo "Ups error message";
JS
this.on('error', function(file, response) {
$(file.previewElement).find('.dz-error-message').text(response);
});
For me this code finally worked, used as a dropzone option:
error: function(file, message) {
$(file.previewElement).addClass("dz-error").find('.dz-error-message').text(message.Message);
}
I used message.Message since the ASP.net WebAPI returns a JSON object, but not with the required "error" key.
You can simply echo back the message from server via PHP file
if($file_uploaded == true)
{
//perform operations on valid upload
} else {
//upload failed, echo back negative response to dropzone.js
$this->output->set_header("HTTP/1.0 400 Bad Request");
echo "Error uploading file";
}
While your HTML file can look like:
<script type="text/javascript">
Dropzone.options.myAwesomeDropzone = {
paramName: "icon_image", // The name that will be used to transfer the file
maxFilesize: 2, // MB
init: function() {
this.on("error", function(file, response) {
// do stuff here.
alert(response);
});
}
};
</script>
Hope it helps :)

Inline support Chat implementation

We are creating a live chat support system. Currently if the visitor clicks on live chat button, a new window opens up and user can talk their. What I am trying to accomplish is to open the chat window inline like this link:
http://anantgarg.com/chat/sampleb.php
Please note that we are building support chat system not peer chat system as the above link intends.
The problem we are facing here is that how we'll be able to access the database which is located on different server (our server) and not on the server where our client's website is located. The above solution can work fine if we are on the same server.
So, please suggest on how to overcome this hurdle.
Thanks.
I think, for solve your task you may use WebSockets, it support cross-domain connections.
In your case, you may write chat client side and place it on cliet's website, but request from it weill processed by your server with DB access.
Extend
Of course you can use JSON with WebSockets just as JSON with AJAX. WebSockets is transport - JSON is content passed with this transport.
I write this code when reserarch WebSockets (chat lietn side):
function connect(){
var socket;
var host = window.location.host;
var wsUrl = "ws://" + host + "/connect";
try{
var socket = new WebSocket(wsUrl);
message('<p class="event">Socket Status: '+socket.readyState);
socket.onopen = function(){
message('<p class="event">Socket Status: '+socket.readyState+' (open)');
//Run "Ping-Pong" for support connection
setTimeout(pingPong, 5000);
}
socket.onmessage = function(msg){
//Parse server answer from string to JSON object
var answer = JSON.parse(msg.data);
if (answer.type == 'message') {
message('<p class="message">'+answer.user+': '+answer.message);
}
}
socket.onclose = function(){
message('<p class="event">Socket Status: '+socket.readyState+' (Closed)');
}
} catch(exception){
message('<p>Error'+exception);
}
function send(){
var text = $('#text').val();
if(text==""){
message('<p class="warning">Please enter a message');
return ;
}
try{
//Send data via JSON
socket.send('{"type": "message", "message":'+JSON.stringify(text)+'}');
} catch(exception){
message('<p class="warning">');
}
$('#text').val("");
}
var token = 0;
function pingPong()
{
token++;
try{
var msg = {'type': 'ping', 'token': token};
socket.send(JSON.stringify(msg));
setTimeout(pingPong, 5000);
} catch(exception){
message('<p class="warning">');
}
}
function message(msg){
$('#chatLog').append(msg+'</p>');
}//End message()
$('#text').keypress(function(event) {
if (event.keyCode == '13') {
send();
}
});
$('#disconnect').click(function(){
socket.close();
});
}
$(document).ready(function() {
if(!("WebSocket" in window)){
$('#chatLog, input, button, #examples').fadeOut("fast");
$('<p>Oh no, you need a browser that supports WebSockets. How about Google Chrome?</p>').appendTo('#container');
}else{
//The user has WebSockets
connect();
}
});
</script>
<meta charset=utf-8 />
<style type="text/css">
body{font-family:Arial, Helvetica, sans-serif;}
#container{
border:5px solid grey;
width:800px;
margin:0 auto;
padding:10px;
}
#chatLog{
padding:5px;
border:1px solid black;
}
#chatLog p{margin:0;}
.event{color:#999;}
.warning{
font-weight:bold;
color:#CCC;
}
</style>
<title>WebSockets Client</title>
</head>
<body>
<div id="wrapper">
<div id="container">
<h1>WebSockets Client</h1>
<div id="chatLog">
</div>
<p id="examples">e.g. try 'hi', 'name', 'age', 'today'</p>
<input id="text" type="text" />
<button id="disconnect">Disconnect</button>
</div>
</div>
</body>
</html>​
Also you can use SocketIO library for it, but I dont sure for it cross-domain work.

Resources