I'm trying to implement FineUploader React library into my React app to upload files to my Azure Blob Storage.
Looks like for some reason, FineUploader is getting the blob storage URI wrong.
This is how I instanciate a FineUploader in my test component:
import React, { Component } from 'react';
import FineUploaderAzure from 'fine-uploader-wrappers/azure'
import Gallery from './gallery/index';
const uploader = new FineUploaderAzure({
options: {
cors: {
expected: true,
sendCredentials: true
},
signature: {
endpoint: 'https://myapp.com/api/getsas'
},
request: {
endpoint: 'https://myaccount.blob.core.windows.net/test-container'
},
uploadSuccess: {
endpoint: 'https://myapp.com/api/done'
}
}
})
class Index extends Component {
render() {
return (
<Gallery uploader={uploader} />
)
}
}
export default Index;
Here's the error I'm seeing in the console. Looks like FineUploader is using the wrong URI for the blob storage.
Any idea what may be causing this?
UPDATE:
As per #GauravMantri's suggestion, I changed endpoint to containerUrl in the options section but that didn't seem to help either. Here's what it looks like:
const uploader = new FineUploaderAzure({
options: {
cors: {
expected: true,
sendCredentials: true
},
signature: {
endpoint: 'https://myapp.com/api/getsas'
},
request: {
containerUrl: 'https://myaccount.blob.core.windows.net/test-container'
},
uploadSuccess: {
endpoint: 'https://myapp.com/api/done'
}
}
})
Here's the SAS I'm getting when I send a request through Postman:
The request I'm sending is:
http://example.com/api/files/get/sas?blobUri=https://myaccount.blob.core.windows.net/test-container/test.txt&_method=put
And here's the SAS I receive:
"?sv=2017-04-17&sr=b&sig=7pXTnI2r8uGyZms12T9cRvHg1XlLI53ZJtwPUwGElnY%3D&st=2017-12-28T14%3A02%3A56Z&se=2017-12-28T14%3A22%3A56Z&sp=w"
I was able to make it work. Basically there're a few things that one need to keep in mind:
In your FineUploader config, you will need endpoint attribute and that should have the URL of the blob container where you want to upload. This is how configuration looks like in my code:
var uploader = new qq.azure.FineUploader({
debug: true,
element: document.getElementById("uploader"),
cors: {
expected: true,
sendCredentials: false
},
signature: {
endpoint: 'http://localhost:63194/users/sas'
},
request: {
endpoint: 'https://account-name.blob.core.windows.net/container-name'
},
})
The API for getting Shared Access Signature (SAS) should return blob URL + SAS Token. The blobUrl parameter to the API should be the absolute URL of the blob. This is the code I used for API (please don't use this as is because the code below does not take into consideration the _method parameter):
[Route("sas")]
[HttpGet]
public async Task<HttpResponseMessage> Sas(string blobUri)
{
var credentials = new StorageCredentials("account-name", "account-key");
var blob = new CloudBlockBlob(new Uri(blobUri), credentials);
var sasParameters = new SharedAccessBlobPolicy()
{
SharedAccessExpiryTime = DateTime.UtcNow.AddHours(1),
Permissions = SharedAccessBlobPermissions.Write
};
var sasToken = blob.GetSharedAccessSignature(sasParameters);
var returnValue = blob.Uri.AbsoluteUri + sasToken;
var resp = new HttpResponseMessage(HttpStatusCode.OK);
resp.Content = new StringContent(returnValue, System.Text.Encoding.UTF8, "text/plain");
return resp;
}
I downloaded Fine Uploader Azure related files from here: https://fineuploader.com/customize.html and used it to create a simple HTML page to test it. Here's what my HTML page looks like:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="fine-uploader-gallery.min.css" rel="stylesheet">
<script src="azure.fine-uploader.min.js""></script>
<script type="text/template" id="qq-template">
<div class="qq-uploader-selector qq-uploader qq-gallery" qq-drop-area-text="Drop files here">
<div class="qq-total-progress-bar-container-selector qq-total-progress-bar-container">
<div role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" class="qq-total-progress-bar-selector qq-progress-bar qq-total-progress-bar"></div>
</div>
<div class="qq-upload-drop-area-selector qq-upload-drop-area" qq-hide-dropzone>
<span class="qq-upload-drop-area-text-selector"></span>
</div>
<div class="qq-upload-button-selector qq-upload-button">
<div>Upload a file</div>
</div>
<span class="qq-drop-processing-selector qq-drop-processing">
<span>Processing dropped files...</span>
<span class="qq-drop-processing-spinner-selector qq-drop-processing-spinner"></span>
</span>
<ul class="qq-upload-list-selector qq-upload-list" role="region" aria-live="polite" aria-relevant="additions removals">
<li>
<span role="status" class="qq-upload-status-text-selector qq-upload-status-text"></span>
<div class="qq-progress-bar-container-selector qq-progress-bar-container">
<div role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" class="qq-progress-bar-selector qq-progress-bar"></div>
</div>
<span class="qq-upload-spinner-selector qq-upload-spinner"></span>
<div class="qq-thumbnail-wrapper">
<img class="qq-thumbnail-selector" qq-max-size="120" qq-server-scale>
</div>
<button type="button" class="qq-upload-cancel-selector qq-upload-cancel">X</button>
<button type="button" class="qq-upload-retry-selector qq-upload-retry">
<span class="qq-btn qq-retry-icon" aria-label="Retry"></span>
Retry
</button>
<div class="qq-file-info">
<div class="qq-file-name">
<span class="qq-upload-file-selector qq-upload-file"></span>
<span class="qq-edit-filename-icon-selector qq-btn qq-edit-filename-icon" aria-label="Edit filename"></span>
</div>
<input class="qq-edit-filename-selector qq-edit-filename" tabindex="0" type="text">
<span class="qq-upload-size-selector qq-upload-size"></span>
<button type="button" class="qq-btn qq-upload-delete-selector qq-upload-delete">
<span class="qq-btn qq-delete-icon" aria-label="Delete"></span>
</button>
<button type="button" class="qq-btn qq-upload-pause-selector qq-upload-pause">
<span class="qq-btn qq-pause-icon" aria-label="Pause"></span>
</button>
<button type="button" class="qq-btn qq-upload-continue-selector qq-upload-continue">
<span class="qq-btn qq-continue-icon" aria-label="Continue"></span>
</button>
</div>
</li>
</ul>
<dialog class="qq-alert-dialog-selector">
<div class="qq-dialog-message-selector"></div>
<div class="qq-dialog-buttons">
<button type="button" class="qq-cancel-button-selector">Close</button>
</div>
</dialog>
<dialog class="qq-confirm-dialog-selector">
<div class="qq-dialog-message-selector"></div>
<div class="qq-dialog-buttons">
<button type="button" class="qq-cancel-button-selector">No</button>
<button type="button" class="qq-ok-button-selector">Yes</button>
</div>
</dialog>
<dialog class="qq-prompt-dialog-selector">
<div class="qq-dialog-message-selector"></div>
<input type="text">
<div class="qq-dialog-buttons">
<button type="button" class="qq-cancel-button-selector">Cancel</button>
<button type="button" class="qq-ok-button-selector">Ok</button>
</div>
</dialog>
</div>
</script>
<title>Fine Uploader Gallery UI</title>
</head>
<body>
<div id="uploader"></div>
<script>
// Some options to pass to the uploader are discussed on the next page
var uploader = new qq.azure.FineUploader({
debug: true,
element: document.getElementById("uploader"),
cors: {
expected: true,
sendCredentials: false
},
signature: {
endpoint: 'http://localhost:63194/users/sas'
},
request: {
endpoint: 'https://account-name.blob.core.windows.net/container-name'
},
})
</script>
</body>
</html>
Once I ran this code, I was able to upload files in my blob container without any problems.
Related
I'm following the IdentityServer3 jsGettingStarted sample github sample
But I'm trying to do so using MVC.
(The IdentityServer itself is in a separate project and solution as per the sample documentation.)
Providing the index.html page is via a Controller-Action, which is fine.
The login popup "popup.html" which is actually "popup.cshtml" is also via a Controller action and it also displays, but it won't close and display the user credentials in the index page as shown in the Sample.
But putting a few alerts in, .. the user is definitely logged in.
I also tried moving the popup.html into the root of the project (as .html and not as .cshtml and changing the server's Client.cs' RedirectUris to reflect that change) but without success.
Is it because of the cshtml pages being served from my controller actions ?
The documentation says that this should display by calling the display function, but the "manager.events.addUserLoaded" function is not firing, which calls the display function.
I am using VS2017 MVC5 with Framework 4.8.
Thanks
<link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.css" />
<script src="~/Scripts/jquery.js"></script>
<script src="~/Scripts/bootstrap.js"></script>
<script src="~/Scripts/oidc-client.js"></script>
<div>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="#">JS Application</a>
</div>
</div>
</nav>
<div class="container main-container">
<div class="row">
<div class="col-xs-12">
<ul class="list-inline list-unstyled requests">
<li>Home</li>
<li><button type="button" class="btn btn-default js-login">Login</button></li>
</ul>
</div>
</div>
<div class="row">
<div class="col-xs-6">
<div class="panel panel-default">
<div class="panel-heading">User data</div>
<div class="panel-body">
<pre class="js-user"></pre>
</div>
</div>
</div>
</div>
</div>
<script language="javascript" type="text/javascript">
// helper function to show data to the user
function display(selector, data)
{
if (data && typeof data === 'string')
{
data = JSON.parse(data);
}
if (data)
{
data = JSON.stringify(data, null, 2);
}
alert("selector=" + data);
$(selector).text(data);
}
var settings = {
authority: 'https://localhost:44302', // The url of the IdentityServer
client_id: 'js',
popup_redirect_uri: 'http://localhost:44888/Account/Popup',
response_type: 'id_token token',
scope: 'openid profile email',
filterProtocolClaims: true
};
var manager = new Oidc.UserManager(settings);
var user;
manager.events.addUserLoaded(function (loadedUser)
{
alert("userManager");
user = loadedUser;
display('.js-user', user);
});
$('.js-login').on('click', function ()
{
manager
.signinPopup()
.catch(function (error)
{
console.error('error while logging in through the current window or popup', error);
});
});
</script>
By creating a standalone project rather than trying to do it in already established project, I managed to get it to work. There were clashes in the scripts and css we were already using.
I'm coding a search form to get some data from database
I don't know what am i doing wrong. The page just refreshes and nothing happens.
1- I have a form with a input called "term"
2- My route: Route.get('/telefone', 'TelefoneController.show')
MY CONTROLLER
async show ({ params, request, response, view }) {
const term = request.input('term');
const nome = await Telefone.query().where('atendente', 'LIKE',
'%'+term+'%').fetch()
console.log(nome);
return view.render('telefone', {
nome: nome,
})
}
MY HTML
<div class="container d-flex">
<form action="{{ route('/telefone')}}" method="get" class="col-sm-8">
<div class="form-group">
<label for="campotel">Buscar Nome</label>
<input type="text" name="term" class="form-control" id="campotel" placeholder="Digite o nome do funcionário">
</div>
<button type="submit" class="btn btn-success float-right">Buscar</button>
</form>
</div>
DB STRUCTURE
class TelefoneSchema extends Schema {
up () {
this.create('telefones', (table) => {
table.increments()
table.string('ramal')
table.string('voip')
table.string('atendente')
table.integer('id_departamento')
.unsigned()
.references('id')
.inTable('departamentos')
.onUpdate('CASCADE')
.onDelete('CASCADE')
table.integer('id_polo_telefone')
.unsigned()
.references('id')
.inTable('polos')
.onUpdate('CASCADE')
.onDelete('CASCADE')
table.timestamps()
})
}
down () {
this.drop('telefones')
}
}
module.exports = TelefoneSchema
page just refresh and nothing happens
I tried on my side without being able to reproduce the case.
But I have some information that might perhaps help you:
When the query returns no value the result is null. -> make sure your db have values
My test code (work fine):
My controller:
'use strict'
const Telefone = use('App/Models/Telefone')
class TelefoneController {
async show ({ params, request, response, view }) {
const term = request.input('term')
console.log(term)
const result = await Telefone.query().where('atendente', 'like',
'%'+term+'%').fetch()
const nome = result.toJSON()
console.log(nome) // Return JSON array
return view.render('welcome', {
nome: nome,
})
}
}
module.exports = TelefoneController
My schema (I don't use all your datas) :
class TelefoneSchema extends Schema {
up () {
this.create('telefones', (table) => {
table.increments()
table.string('ramal')
table.string('voip')
table.string('atendente')
table.timestamps()
})
}
down () {
this.drop('telefones')
}
}
My view :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Hello Adonis</title>
</head>
<body>
<h1>Ramal : {{ nome[0].ramal }}</h1>
<div class="container d-flex">
<form action="{{ route('/telefone')}}" method="get" class="col-sm-8">
<div class="form-group">
<label for="campotel">Buscar Nome</label>
<input type="text" name="term" class="form-control" id="campotel" placeholder="Digite o nome do funcionário">
</div>
<button type="submit" class="btn btn-success float-right">Buscar</button>
</form>
</div>
</body>
</html>
I hope it might help you a little bit.
I have some code that I wrote to essentially handle a login with a back end API supporting it.
My problem is that after the form POSTS the data to the server (and it is accepted), the index page (which is the same place this form is located on) still shows the login form instead of the different if statement I have in the file.
BUT, if I refresh the page, the correct part of the if statement displays. I have been at this all day, and I need a fresh pair of eyes to look over it and see what I'm doing something wrong:
define([
'lodash',
'log4js',
'path',
'when',
'common/lang/Disposable',
'common/commands/CommandHandler',
'common-node/network/http/Verb',
'common-node/network/server/endpoints/html/PageContainer',
'common-node/network/server/endpoints/html/PageEndpoint',
'common-node/network/server/ServerDefinition',
'common-node/network/server/ServerFactory.instance',
], function(_, log4js, path, when, Disposable, CommandHandler, Verb, PageContainer, PageEndpoint, ServerDefinition, serverFactory) {
//'use strict';
var m;
var session = require('client-sessions');
session({
cookieName: 'GBE_OWNED',
secret: '12112asdfasdf',
duration: 30 * 60 * 1000,
activeDuration: 5 * 60 * 1000,
});
var logger = log4js.getLogger('server/GbeSeasonalsWebServer');
var GbeSeasonalsWebServer = Disposable.extend({
init: function() {
},
start: function(configuration) {
var port = getContainerPort(configuration.container);
var state = false;
var indexHandler = new CommandHandler.fromFunction(function(input) {
console.log(input || { });
if(input.logout == ''){
session.qry = '';
session.Name = '';
return {
name: '',
currentState: false,
reloadLogout: true
};
}
if(typeof session.qry === 'undefined' || session.qry === null || session.qry === ''){
//the user isn't logged in
state = false;
}
else{
console.log(session.qry);
state = true;
}
return {
name: session.Name,
currentState: state
};
});
var loginHandler = new CommandHandler.fromFunction(function(input) {
var userName = input.username;
var userPass = input.password;
var rememberMe = input.remember;
var retro = false;
var iResponse;
var productIDs = 'USC_SEASONAL_CB,USC_SEASONAL_CB'; // this will be changed when jose gets back to me with the specifics
var https = require('https');
var callback = function(response){
var str = '';
response.on('data', function(chunk){
str += chunk;
});
response.on('end', function () {
try{
var DOMParser = require('xmldom').DOMParser;
}catch(err){
return {error: "There appeared to be an error. Please try again."};
}
var doc = new DOMParser().parseFromString(str,'text/xml');
var isSuccessful = doc.firstChild.attributes[1].nodeValue;
if(isSuccessful == 'True'){
retro = true;
//I need to set a session here
console.log("The account was logged in successfully.");
session.qry = '?username=' + userName + '&password=' + userPass + '&productids=' + productIDs;
//console.log(session.username);
if(typeof str === 'undefined' || str === null){return {error: "There appeared to be an error. Please try again."};}
session.Name = doc.firstChild.attributes[4].nodeValue + ' ' + doc.firstChild.attributes[5].nodeValue;
var state = true;
iResponse = function (){
return {
name: session.Name,
currentState: true,
reload: true,
};
};
}
else{
iResponse = function (){
return {
error: "There appeared to be a problem while trying to log you in.",
name: "WHATTHEHELL",
state: false
};
};
}
return iResponse;
});
response.on('error', function (e) {
console.log(e);
});
};
return https.request('https://secure.barchart.com/banker/getuserpermissions.ashx?username=' + userName + '&password=' + userPass + '&productids=' + productIDs, callback).end();
});
var definition = ServerDefinition
.withContainer(
new PageContainer(port, '/')
.addEndpoint(new PageEndpoint(Verb.GET, '', 'index', indexHandler))
.addEndpoint(new PageEndpoint(Verb.POST, '', 'index', loginHandler))
.addEndpoint(new PageEndpoint(Verb.GET, '/index', 'index', indexHandler))
.addEndpoint(new PageEndpoint(Verb.POST, '/index', 'index', loginHandler))
.addEndpoint(new PageEndpoint(Verb.GET, '/signup', 'signup'))
.addEndpoint(new PageEndpoint(Verb.POST, '/signup', 'signup'))
.addEndpoint(new PageEndpoint(Verb.GET, '/more', 'more'))
);
definition.withTemplatePath(path.join(configuration.server.path, configuration.container.http.templatePath));
_.forEach(configuration.container.http.staticPaths, function(filePath, serverPath) {
definition.withStaticPath(path.join(configuration.server.path, filePath), serverPath);
});
return when.try(function() {
serverFactory.build(definition);
}).then(function() {
return true;
});
},
_onDispose: function() {
logger.warn('GBE Seasonals web server is being disposed');
},
toString: function() {
return '[GbeSeasonalsWebServer]';
}
});
function getContainerPort(containerConfiguration) {
var port = parseInt(process.env.PORT);
if (_.isNaN(port)) {
port = null;
}
return port || containerConfiguration.port || 8080;
}
return GbeSeasonalsWebServer;
});
And the index page:
<!DOCTYPE html>
<html lang="en">
<head>
<title>GBE SEASONALS STAGING SITE © Barchart™</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<!-- Custom theme -->
<link rel="stylesheet" type="text/css" href="static/css/custom.css">
</head>
<body>
<script type="text/javascript">
var c = '{{name}}';
var state = '{{currentState}}';
{{#if reload}}
window.location = window.location.href;
{{/if}}
{{#if reloadLogout}}
window.location = window.location.href.split("?")[0];
{{/if}}
if(state==''){window.location = window.location.href; }
</script>
<div class="container">
<div class = "row">
<div class="col-md-10 col-md-offset-1">
<a href="index">
<img style = "vertical-align:middle;display:inline-block" src="http://www.gbemembers.com/images/GBE_Logo_horiz.png" class="img-responsive">
<p style="color:white;margin-top:50px;margin-right:20px;font-size:20px" class="pull-right">Seasonals</p>
</a>
</div>
</div>
<div class="row">
<div class="col-md-10 col-md-offset-1">
<div class="panel panel-default">
<div class="panel-heading"></div>
<div class="panel-body">
<div class = "row">
{{#if error}}
<div class="alert alert-danger" role="alert">
<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
<span class=""><b>Error:</b></span>
{{error}}
</div>
{{/if}}
{{#if currentState}}
<div class = "col-md-12">
<p class = "pull-right">Welcome back {{name}}! Click here to log out.</p>
</div>
{{else}}
<center>
<div class = "col-md-12">
<form class="form-inline" style = "width:100%;margin:0 auto;" method="post" action = "?"><label>Already a member? Login here: </label>
<div class="form-group">
<label class="sr-only" for="exampleInputEmail3">Email address</label>
<input type="" class="form-control" id="exampleInputEmail3" placeholder="Email" name = "username">
</div>
<div class="form-group">
<label class="sr-only" for="exampleInputPassword3">Password</label>
<input type="password" class="form-control" id="exampleInputPassword3" placeholder="Password" name = "password">
</div>
<div class="checkbox">
<label>
<input type="checkbox" name = "remember"> Remember me
</label>
</div>
<button type="submit" class="btn btn-default">Sign in</button>
<input type = "button" value = "Register" class="btn btn-default">
</form>
<p></p>
</div>
</center>
{{/if}}
</div>
<div class = "row">
<div class = "col-md-12">
<div class="jumbotron">
<h1>Hello, world!</h1>
<p>This is an example of a jumbotron....because you're worth it.</p>
<p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more</a></p>
</div>
</div>
</div>
<div class = "row">
<div class = "col-md-12">
<p>
Freegan tacos before they sold out, health goth sriracha chartreuse kinfolk jean shorts man braid artisan literally. Brooklyn vice hashtag, meh tumblr kombucha marfa readymade. Ennui cold-pressed distillery freegan. Kale chips tilde +1, mumblecore franzen migas paleo. Offal 3 wolf moon before they sold out, health goth disrupt fixie bitters flannel meditation pop-up flexitarian irony meh. Deep v put a bird on it pork belly cardigan etsy. Lumbersexual literally crucifix slow-carb cardigan.
</p>
</div>
</div>
<div class = "row">
<div class = "col-md-12">
<p>Asymmetrical readymade brooklyn, blue bottle master cleanse disrupt artisan +1 actually affogato roof party DIY polaroid next level retro. Brooklyn poutine vegan bitters you probably haven't heard of them. Celiac helvetica master cleanse williamsburg, synth shabby chic fixie. Viral typewriter cred, roof party kombucha readymade offal shabby chic meggings. Gochujang chillwave VHS food truck. Ennui ugh twee, mumblecore sriracha DIY gastropub hella 3 wolf moon pabst kale chips typewriter trust fund direct trade. Neutra microdosing selfies listicle.</p>
</div>
</div>
<div class = "row">
<div class = "col-md-12">
<p>
Gochujang farm-to-table offal, distillery tofu migas skateboard 90's. Ethical ramps hoodie, YOLO vice before they sold out four loko literally mustache post-ironic. Fixie ennui literally lumbersexual photo booth umami disrupt messenger bag man braid polaroid. Cold-pressed aesthetic marfa, vinyl truffaut squid 3 wolf moon sriracha keytar knausgaard echo park. Chambray leggings microdosing mustache migas. Keytar portland chambray, quinoa ugh farm-to-table mustache cred mixtape craft beer. Thundercats chia keytar beard, drinking vinegar mustache man bun slow-carb wayfarers polaroid lo-fi chicharrones.
</p>
</div>
</div>
<div class = "row">
<div class = "col-md-12">
<p>
Quinoa cred taxidermy, cold-pressed microdosing offal mustache gluten-free small batch tousled twee wayfarers. Wolf williamsburg normcore lo-fi, tilde seitan hammock bushwick DIY organic single-origin coffee quinoa microdosing man braid. Fap small batch PBR&B microdosing, migas pork belly occupy aesthetic pop-up slow-carb 3 wolf moon. Blue bottle XOXO occupy +1, pabst lomo chicharrones ethical heirloom helvetica asymmetrical. Bushwick shabby chic yr kombucha, flannel truffaut raw denim banh mi bitters gluten-free pickled hoodie letterpress sartorial. YOLO whatever tacos meggings venmo, keytar knausgaard mumblecore. Tilde waistcoat offal, locavore cred umami mlkshk vice lomo lo-fi tousled selvage blog tattooed poutine.
</p>
</div>
</div>
<div class = "row">
<div class = "col-md-12">
<button type="button" class="btn btn-primary btn-lg btn-block">Click here to sign up!</button>
</div>
</div>
</div>
<div class = "panel-footer">GBE Seasonal © 2016 Barchart</div>
</div>
</div>
</div>
</div> <!-- /container -->
<!-- Let's load the javascript dendencies now -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
<script type="text/javascript" src = "http://getbootstrap.com/assets/js/ie10-viewport-bug-workaround.js"></script>
</body>
</html>
I believe it is a session issue, but I cannot seem to get around the issue. What's more, I cannot even get the callback function to return the needed data.
I'm currently teaching myself the ins and outs of building a MEAN app. I started with the basic todo app and modified it pretty heavily to support multiple key value pairs and have updated the UI using bootstrap.
It's currently hosted here: http://surveymanager-30817.onmodulus.net/
I've implemented ui-sortable, and it works perfectly by itself.
The challenge I'm having, that I cannot seem to find any relevant documentation or tutorials for - is how to communicate the updated sort order to mongo so when I refresh the page, ng-repeat will repeat question in questions with the order that I had previously created.
Here is the HTML
<!-- index.html -->
<!doctype html>
<!-- ASSIGN OUR ANGULAR MODULE -->
<html ng-app="QuestionManager">
<head>
<!-- META -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"><!-- Optimize mobile viewport -->
<title>Question Manager</title>
<!-- SCROLLS -->
<link href="css/bootstrap.min.css" rel="stylesheet">
<link href="css/question-bootstrap.css" rel="stylesheet">
<style>
html { overflow-y:scroll; }
body { padding-top:30px; }
#todo-list { margin-bottom:30px; }
</style>
<!-- SPELLS -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script><!-- load jquery -->
<script src="//code.jquery.com/ui/1.9.1/jquery-ui.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script><!-- load angular -->
<script src="js/sortable.js"></script>
<script src="core.js"></script>
</head>
<!-- SET THE CONTROLLER AND GET ALL TODOS -->
<body ng-controller="mainController">
<div class="container sm_head">
<div class="col-sm-6">
</div>
<div class="col-sm-6">
<h2 class="pull-right">Survey Manager</h2>
</div>
</div>
<div class="container">
<!-- Nav tabs -->
<ul id="navtabs" class="nav nav-tabs" role="tablist">
<li class="active">Manage</li>
<li>Create</li>
<li>Render Code</li>
<li>About</li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<div class="tab-pane active" id="manage">
<div class="panel panel-default">
<!-- Default panel contents -->
<div class="panel-heading">Manage Question Order<span class="badge pull-right">{{ questions.length }} Questions</span></div>
<!-- Table -->
<table class="table">
<thead>
<tr>
<th>Order</th>
<th>Question Name</th>
<th>Evergage Field</th>
<th>Username</th>
<th>Options</th>
</tr>
</thead>
<tbody ui-sortable="sortableOptions" ng-model="questions">
<tr ng-repeat="question in questions">
<td>{{ question.order }}</td>
<td>{{ question.meanName }}</td>
<td>{{ question.fieldName }}</td>
<td>#mdo</td>
<td>
<button type="button" class="btn btn-default btn-sm" ng-click="deleteQuestion(question._id)">
<span class="ques-list glyphicon glyphicon-remove"></span> delete </button>
</td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-8">
<form class="form-horizontal">
<fieldset>
<!-- Form Name -->
<legend>Question Details</legend>
<!-- Text input-->
<div class="form-group">
<label class="col-md-4 control-label" for="Question Name">Question Order</label>
<div class="col-md-8">
<input id="Question Order" name="Question Order" type="text" placeholder="Question Order" class="form-control input-md" ng-model="formData.order">
</div>
</div>
<!-- Text input-->
<div class="form-group">
<label class="col-md-4 control-label" for="Question Name">Question Name</label>
<div class="col-md-8">
<input id="Question Name" name="Question Name" type="text" placeholder="Write something meaningful" class="form-control input-md" ng-model="formData.meanName">
</div>
</div>
<!-- Text input-->
<div class="form-group">
<label class="col-md-4 control-label" for="Custom Field Name">Custom Field</label>
<div class="col-md-8">
<input id="Custom Field Name" name="Custom Field Name" type="text" placeholder="Format: User.Profile.xx.xx.xx ( 1 or 3 additional words)" class="form-control input-md" ng-model="formData.fieldName">
</div>
</div>
<!-- Button -->
<div class="form-group">
<label class="col-md-4 control-label" for="Create"></label>
<div class="col-md-4">
<button id="Create" name="Create" class="btn btn-primary" ng-click="createQuestion()">Create</button>
</div>
</div>
</fieldset>
</form>
</div>
</div>
<div class="tab-pane" id="create">
</div>
<div class="tab-pane" id="render">...</div>
<div class="tab-pane" id="about">...</div>
</div>
</div>
<script src="js/bootstrap.min.js"></script>
</body>
</html>
Here is the client side:
// public/core.js
var QuestionManager = angular.module('QuestionManager', ['ui.sortable']);
function mainController($scope, $http) {
$scope.formData = {};
// when landing on the page, get all questions and show them
$http.get('/api/questions')
.success(function(data) {
$scope.questions = data;
console.log(data);
})
.error(function(data) {
console.log('Error: ' + data);
});
// when submitting the add form, send the text to the node API
$scope.createQuestion = function() {
$http.post('/api/questions', $scope.formData)
.success(function(data) {
$scope.formData = {};
console.log('fuck you!');
$scope.questions = data;
console.log(data);
})
.error(function(data) {
console.log('Error: ' + data);
});
};
// delete a question after checking it
$scope.deleteQuestion = function(id) {
$http.delete('/api/questions/' + id)
.success(function(data) {
$scope.questions = data;
console.log(data);
})
.error(function(data) {
console.log('Error: ' + data);
});
};
$scope.$watch("questions", function(newVal, oldVal) {
console.log("oldval", oldVal);
console.log("newVal", newVal);
});
$scope.sortableOptions = {
update: function(e, ui) {
$http.put('/api/questions', $scope.questions)
console.log($scope.questions);
},
axis: 'y'
};
}
// Some Bootstrap Initializers
$('#navtabs>li a').click(function (e) {
e.preventDefault()
$(this).tab('show')
})
And here is the server side with my random test and console logs starting at line 44
// server.js
var express = require('express');
var app = express(); // create our app w/ express
var mongoose = require('mongoose'); // mongoose for mongodb
var morgan = require('morgan'); // log requests to the console (express4)
var bodyParser = require('body-parser'); // pull information from HTML POST (express4)
var methodOverride = require('method-override'); // simulate DELETE and PUT (express4)
mongoose.connect('mongodb://ewill3532:12qwaszx#proximus.modulusmongo.net:27017/pUxo2hir'); // connect to mongoDB database locally
app.use(express.static(__dirname + '/public')); // set the static files location /public/img will be /img for users
app.use(morgan('dev')); // log every request to the console
app.use(bodyParser.urlencoded({'extended':'true'})); // parse application/x-www-form-urlencoded
app.use(bodyParser.json()); // parse application/json
app.use(bodyParser.json({ type: 'application/vnd.api+json' })); // parse application/vnd.api+json as json
app.use(methodOverride());
var question = mongoose.model('question', {
order : String,
fieldName : String,
meanName : String
});
app.get('/api/questions', function(req, res) {
// use mongoose to get all questions in the database
question.find(function(err, questions) {
// if there is an error retrieving, send the error. nothing after res.send(err) will execute
if (err)
res.send(err)
res.json(questions); // return all questions in JSON format
});
});
// create todo and send back all questions after creation
app.post('/api/questions', function(req, res) {
// create a todo, information comes from AJAX request from Angular
question.create({
order : req.body.order,
fieldName : req.body.fieldName,
meanName : req.body.meanName,
done : false
}, function(err, todo) {
if (err)
res.send(err);
// get and return all the questions after you create another
question.find(function(err, questions) {
if (err)
res.send(err)
res.json(questions);
});
});
});
// delete a todo
app.delete('/api/questions/:todo_id', function(req, res) {
question.remove({
_id : req.params.todo_id
}, function(err, todo) {
if (err)
res.send(err);
// get and return all the questions after you create another
question.find(function(err, questions) {
if (err)
res.send(err)
res.json(questions);
});
});
});
// let's just put this here so that it comes back as found
app.put('/api/questions', function(req, res) {
});
app.get('*', function(req, res) {
res.sendfile('./public/index.html'); // load the single view file (angular will handle the page changes on the front-end)
});
// listen (start app with node server.js) ======================================
app.listen(8080);
console.log("App listening on port 8080");
Any help here, or if someone can point me to some good documentation or tutorials - either way would be very helpful!'
Thanks!
I have to send data using socket.io.when a user enter his login and a password,he will be redirect to index.ejs and the username will be send to the server.
route.js (I mentioned only the part of the script not the hole script to show that when the login and password are correct a user get an index page and the userobject send to the index):
var index = function(req, res, next) {
if(!req.isAuthenticated()) {
res.redirect('/signin');
} else {
var user = req.user;
if(user !== undefined) {
user = user.toJSON();
}
res.render('index', {title: 'Home', user: user});
}
};
app.js:
io.sockets.on('connection', function (socket) {
socket.on("new_user",function(user1){
console.log("a new user is connected",user1);
var current_date=new Date();
var date=current_date.toString();
ex.user_connect(user1,date);
});
});
index.ejs:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width ,initial-scale=1.0" />
<title><%= title %></title>
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="style/style.css"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="js/bootstrap.js"></script>
</head>
<body>
<nav class="navbar navbar-inverse">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="/">HomePage</a>
</div>
<div>
<ul class="nav navbar-nav navbar-right">
<li><%= user.username%></li>
<li><span class="glyphicon glyphicon-log-out"></span> Sign out</li>
</ul>
</div>
</div>
</nav>
<div class="container">
<div class="jumbotron">
<div class="row">
<div class="col-sm-6">
<div class="container">
<h2>Led1</h2>
<!-- Trigger the modal with a button -->
<button type="button" class="btn btn-default btn-lg" id="led1" align="center">check it</button>
<!-- Modal -->
<div class="modal fade" id="model_led1" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header" style="padding:35px 50px;">
<button type="button" class="close" data-dismiss="modal" id="close">×</button>
<h4><span class="glyphicon glyphicon-lock"></span> Settings</h4>
</div>
<div class="modal-body" style="padding:40px 50px;">
<form role="form">
<img src="style/images/led.png" id="led" class="img-responsive"/>
<button type="button" class="btn btn-success btn-block" id="led1_activ"><span class="glyphicon glyphicon-off"></span> Activate</button>
<button type="button" class="btn btn-success btn-block" id="led1_desactiv"><span class="glyphicon glyphicon-off"></span> Desactivate</button>
</form>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-danger btn-default pull-left" data-dismiss="modal" id="cancel_button"><span class="glyphicon glyphicon-remove"></span> Cancel</button>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('http://localhost:3000');
var user1 = user.username;
socket.emit('new_user',user1);
</script>
NB:I got the username on the navbar but I don't get it on the server console.
Ejs render all template variables in server and then return plain html to the client , so
Inside your script , do you have variable global user initialized? :
var user1 = user.username // var user = {username:"foo":} ,something like that before.
If you trying to get user from template variable you could try:
var user1= "<%= user.username%>";
This will render <%= user.username%> inside script tag before send to the client ( browser)