I think this is a scoping problem, but I can't get my head around this.
I have a service as below:
(function (module) {
var portalService = function ($timeout, $http, $q, alerting, $cookies, $cookieStore, STATUS_OK, STATUS_FAIL, APP_COOKIE) {
var _permissions = {};
var permissions = function ()
{
var def = $q.defer();
if (loggedIn) {
if (_.size(_permissions) > 0) {
def.resolve({ status: STATUS_OK }, _permissions);
}
else {
$http({
url: "/Auth/GetPermissionsAsync",
method: "POST",
}).success(function (data, status, headers, config) {
if (data.result.status == STATUS_OK) {
_permissions = data.permissions;
}
def.resolve(data.result, data.permissions);
}).error(function (data, status, headers, config) {
def.reject("Failed to retrieve permissions.", status);
});
}
}
else {
def.resolve({ status: STATUS_OK }, _permissions);
}
return def.promise;
}
var logOn = function (email, password) {
var def = $q.defer();
$http({
url: "/Auth/LogInAsync",
method: "POST",
data: { email: email,
password: password},
}).success(function (data, status, headers, config) {
//testing if we can even update this...
_permissions=[{parent: "Administer", items: [{name: "Users", route: "dashboard"}]}];
def.resolve(data.result);
}).error(function (data, status, headers, config) {
def.reject("Failed to contact the server to log in.",status);
});
return def.promise;
};
var register = function (data) {
var def = $q.defer();
$http({
url: "/Auth/RegisterAsync",
method: "POST",
data: data
,
}).success(function (data, status, headers, config) {
def.resolve(data.result);
}).error(function (data, status, headers, config) {
def.reject("Registration failed to contact the server",status);
});
return def.promise;
};
var logOut = function (data) {
var def = $q.defer();
$http({
url: "/Auth/SignOutAsync",
}).success(function (data, status, headers, config) {
_permissions = {};
def.resolve(data.result);
}).error(function (data, status, headers, config) {
def.reject("Signing out failed to contact the server.", status);
});
return def.promise;
};
var loggedIn = function ()
{
if ($cookies.get(APP_COOKIE))
return true;
else
return false;
}
var currentPermissions = function ()
{
return _permissions;
}
return {
logOn: logOn,
register: register,
logOut: logOut,
loggedIn: loggedIn,
permissions: permissions,
currentPermissions : _permissions
};
};
module.factory("portalService", portalService);
}(angular.module("clportal")));
I have a directive as below:
(function (module) {
var navMenu = function (portalService) {
return {
restrict: "AE",
templateUrl: "/Template/NavMenu",
scope: true,
link: function(scope, element, attributes) {
scope.permissions = portalService.currentPermissions;
}
};
};
module.directive("navmenu", navMenu);
}(angular.module("clportal")));
And, I have the inclusions as below:
<!DOCTYPE html>
<html lang="en" ng-app="clportal">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" href="/favicon.ico">
<title>Navbar Template for Bootstrap</title>
<!-- Bootstrap core CSS -->
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" integrity="sha512-dTfge/zgoMYpP7QbHy4gWMEGsbsdZeCXz7irItjcC3sPUFtf0kuFbDz/ixG7ArTxmDjLXDmezHubeNikyKGVyQ==" crossorigin="anonymous">
<link rel="stylesheet" href="~/lib/angular-growl-v2/build/angular-growl.min.css" />
<link rel="stylesheet" href="~/lib/angular-ui-router-anim-in-out/css/anim-in-out.css" />
<link rel="stylesheet" href="~/lib/font-awesome/css/font-awesome.min.css">
<!-- Custom styles for this template -->
<link href="~/css/site.css" rel="stylesheet">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="container">
<!-- Static navbar -->
<div ng-controller="navController">
<nav class="navbar navbar-default" role="navigation">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle" ng-init="navCollapsed = true" ng-click="navCollapsed = !navCollapsed">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Customer Center</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" ng-class="!navCollapsed && 'in'">
<navmenu></navmenu>
</div><!-- /.navbar-collapse -->
</nav>
</div>
<!-- Main component for a primary marketing message or call to action -->
<div growl inline="true" reference="global"></div>
<div class="row" >
<route-loading-indicator></route-loading-indicator>
<div ng-if="!isRouteLoading" ui-view="" class="col-lg-12 anim-in-out anim-fade" data-anim-speed="1000" ></div>
</div>
</div> <!-- /container -->
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="~/lib/angular/angular.min.js"></script>
<script src="~/lib/angular-ui-router/release/angular-ui-router.min.js"></script>
<script src="~/lib/angular-messages/angular-messages.min.js"> </script>
<script src="~/lib/angular-sanitize/angular-sanitize.min.js"></script>
<script src="~/lib/angular-animate/angular-animate.min.js"></script>
<script src="~/lib/angular-bootstrap/ui-bootstrap-tpls.min.js"></script>
<script src="~/lib/angular-cookies/angular-cookies.min.js"></script>
<script src="~/lib/angular-ui-router-anim-in-out/anim-in-out.js"></script>
<script src="~/js/app/app-clportal.js"> </script>
<script src="~/lib/angular-growl-v2/build/angular-growl.min.js"></script>
<script src="~/js/app/services/exceptionHandler.js"></script>
<script src="~/js/app/services/portalService.js"> </script>
<script src="~/js/app/services/alerting.js"></script>
<script src="~/js/app/directives/alert.js"></script>
<script src="~/js/app/directives/compareDirective.js"> </script>
<script src="~/js/app/directives/formInput.js"></script>
<script src="~/js/app/controllers/homeController.js"> </script>
<script src="~/js/app/controllers/loginController.js"> </script>
<script src="~/js/app/controllers/registerController.js"> </script>
<script src="~/js/app/directives/loadingView.js"></script>
<script src="~/js/app/controllers/dashboardController.js"></script>
<script src="~/js/app/controllers/navController.js"></script>
<script src="~/js/app/directives/navMenu.js"></script>
<script src="~/lib/underscore/underscore-min.js"></script>
</body>
</html>
Now when I call the logOn method, via the portalService, in theory it should set the _permissions local variable, which then should update the appropriate directive navMenu so that it sees the new menu option, and renders appropriately. However this does not work. I can use simple examples and its fine, but there is something fundamentally wrong with the way I'm doing it, scoping wise I would assume and I can't see it.
Any help appreciated.
Thanks
It was just a simple bug - LogOff was being called before log on, and that was setting the local variable to an empty object - this basically cut off the reference that was stored against the directive.
So I needed to set the size to zero on the array if i wanted to clear it out, to make sure that the original reference wasn't lost, and use push to push new values to the array. Working fine now.
Related
I am having this issue with my home button not adding headers in a get request. I have stored a token inside of the localStorage and I send it in the headers when I make a get request to Controller: Home Action: Index. From what I see, it doesn't use my jquery and goes straight to the Account/Index.
Initially, I though it was a problem with the javascript not binding to a button click. After further investigation, I found that the Console.log() I have in _Layout.cshtml do not work and neither does the button. This leads me to believe there is a problem with $("html").html(response); in the Login.js file.
The correct flow is LoginPage -> Login.js (grabs data and uses Ajax for a post request.) -> Returns a html page composing of _Layout.cshtml and /Views/Home/Index.cshtml
Below is my code for the file "Views/Shared/_Layout.cshtml":
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>#ViewData["Title"] - Chat </title>
<environment include="Development">
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="~/css/site.css" />
</environment>
<environment exclude="Development">
<link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/css/bootstrap.min.css"
asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
<link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
</environment>
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li id="li_btnHome"><a asp-area="" asp-controller="" asp-action="">Home</a></li>
</ul>
</div>
</div>
</nav>
<div class="container body-content">
#RenderBody()
<hr />
<footer>
<p>© 2018 - Chat</p>
</footer>
</div>
<environment include="Development">
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
<script type="text/javascript">
console.log("Development");
</script>
</environment>
<environment exclude="Development">
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-3.3.1.min.js"
asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
asp-fallback-test="window.jQuery"
crossorigin="anonymous"
integrity="sha384-tsQFqpEReu7ZLhBV2VZlAu7zcOV+rXbYlF2cqB8txI/8aZajjp4Bqd+V6D5IgvKT">
</script>
<script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/bootstrap.min.js"
asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js"
asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"
crossorigin="anonymous"
integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa">
</script>
<script src="~/js/site.min.js" asp-append-version="true"></script>
<script type="text/javascript">
console.log("Not Development");
</script>
</environment>
<script type="text/javascript">
console.log("Hello World");
</script>
<!--<script src="~/js/NavBarFunction.js"></script>-->
#RenderSection("Scripts", required: false)
</body>
</html>
Here's the javascript file "wwwroot/js/NavBarFunctions.js":
$("#li_btnHome a")[0].onclick = function (event) {
event.preventDefault();
alert("called click");
var tokenObj = localStorage.getItem("token");
var tokenStr = tokenObj == null ? "what_about_tokenObj_is_null?" : tokenObj.toString();
$.ajax({
type: 'GET',
contentType: 'application/json; charset=utf-8;',
url: '#Url.Action("Index", "Home")',
beforeSend: function (xhr) {
xhr.setRequestHeader("Authorization", tokenStr);
},
success: function (response) {
alert(1);
$("html").html(response);
}
});
return false;
};
Here's the HomeController, located in "Controllers/HomeController":
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Chat.Enums;
using Chat.Identity;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
namespace _Chat.Controllers
{
public class HomeController : Controller
{
private AuthenticateUser authenticateUser = new AuthenticateUser();
public async Task<IActionResult> Index()
{
var request = Request;
var headers = request.Headers;
StringValues token;
if (headers.TryGetValue("Authorization", out token))
{
var result = await this.authenticateUser.ValidateToken(token);
if (result.Result == AuthenticateResult.Success)
{
return View();
}
else
{
return RedirectToAction("Index", "Account");
}
}
return RedirectToAction("Index", "Account");
}
}
}
For some odd reason, it looks like after my page is redirected from log in to home, all scripts/javascript stop working.
Here's the code authenticating login. Located in "Controllers/AccountController":
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Chat.Models;
using Chat.DatabaseAccessObject;
using Chat.Identity;
using Chat.DatabaseAccessObject.CommandObjects;
using System.Linq.Expressions;
using System.Net.Mime;
using System.Security.Claims;
using System.Text;
using Microsoft.AspNetCore.Authentication;
using Microsoft.IdentityModel.Tokens;
namespace Chat.Controllers
{
public class AccountController : Controller
{
private const string SECRET_KEY = "CHATSECRETKEY";
public static SymmetricSecurityKey SIGNING_KEY = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SECRET_KEY));
private ServerToStorageFacade serverToStorageFacade = new ServerToStorageFacade();
private AuthenticateUser authenticateUser = new AuthenticateUser();
public IActionResult Index()
{
return View();
}
// Post: /login/
[HttpPost]
public async Task<IActionResult> Login([FromBody]LoginModel loginModel)
{
if (ModelState.IsValid)
{
var mapLoginModelToUser = new MapLoginModelToUser();
var user = await mapLoginModelToUser.MapObject(loginModel);
// If login user with those credentials does not exist
if(user == null)
{
return BadRequest();
}
else
{
var result = await this.authenticateUser.Authenticate(user);
if(result.Result == Chat.Enums.AuthenticateResult.Success)
{
// SUCCESSFUL LOGIN
// Creating and storing cookies
var token = Json(new
{
data = this.GenerateToken(user.Email, user.PantherID),
redirectUrl = Url.Action("Index","Home"),
success = true
});
return Ok(token);
}
else
{
// Unsuccessful login
return Unauthorized();
}
}
}
return BadRequest();
}
private string GenerateToken(string email, string pantherId)
{
var claimsData = new[] { new Claim(ClaimTypes.Email, email), new Claim(ClaimTypes.Actor, pantherId) };
var signInCredentials = new SigningCredentials(SIGNING_KEY, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: "localhost",
audience: "localhost",
expires: DateTime.Now.AddDays(7),
claims: claimsData,
signingCredentials: signInCredentials
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public async Task<IActionResult> Error() => View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
public class MapLoginModelToUser
{
private ServerToStorageFacade serverToStorageFacade;
public MapLoginModelToUser()
{
serverToStorageFacade = new ServerToStorageFacade();
}
public async Task<User> MapObject(LoginModel loginModel)
{
Expression<Func<User, bool>> expression = x => x.Email == loginModel.inputEmail;
var user = await this.serverToStorageFacade.ReadObjectByExpression(new User(Guid.NewGuid()), expression);
if(user == default(Command))
{
return null;
}
return new User(user.ID)
{
Email = loginModel.inputEmail,
Password = loginModel.inputPassword,
FirstName = user.FirstName,
LastName = user.LastName,
PantherID = user.PantherID,
ClassDictionary = user.ClassDictionary,
UserEntitlement = user.UserEntitlement
};
}
}
}
Also the code that renders the page. Located in "wwwroot/js/Login.js":
$(document).ready(function () {
$("#formSubmit").submit(function (event) {
event.preventDefault();
var email = $("#inputEmail").val();
var password = $("#inputPassword").val();
var remember = $("#rememberMe").val();
var loginModel = {
inputEmail: email,
inputPassword: password,
rememberMe: remember
};
$.ajax({
type: 'POST',
url: 'Account/Login',
data: JSON.stringify(loginModel),
contentType: 'application/json; charset=utf-8;',
success: function (response) {
var token = response.value.data;
localStorage.setItem("token", token);
alert("You have successfully logged in.");
setHeader();
redirect(response.value.redirectUrl);
}
});
});
function setHeader() {
$.ajaxSetup({
beforeSend: function (xhr) {
xhr.setRequestHeader('Authorization', localStorage.getItem("token"));
}
});
}
function redirect(redirectUrl) {
$.ajax({
type: 'GET',
contentType: 'application/json; charset=utf-8;',
url: redirectUrl,
success: function (response) {
$("html").html(response);
}
});
}
});
This is the error received after loading the new html page:
EDIT: This is what's sent in the response after the Home button is clicked.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Login - Chat FIU</title>
<link rel="stylesheet" href="/lib/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="/css/site.css" />
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a id="btnHome" href="/">Home</a></li>
</ul>
</div>
</div>
</nav>
<div class="container body-content">
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<link href="/css/signin.css" rel="stylesheet">
<script src="/lib/jquery/dist/jquery.js"></script>
<script src="/lib/bootstrap/dist/js/bootstrap.js"></script>
<script src="/js/Login.js"></script>
</head>
<body class="text-center">
<form id="formSubmit" method="post" class="form-signin">
<img class="mb-4" src="/images/FIU-Chat-Curved.png" alt="" width="150" height="150">
<h1 class="h3 mb-3 font-weight-normal">Please sign in</h1>
<label for="inputEmail" class="sr-only">Email address</label>
<input autofocus="" class="form-control" data-val="true" data-val-required="The Email field is required." id="inputEmail" name="inputEmail" placeholder="Email address" required="required" type="email" value="" />
<label for="inputPassword" class="sr-only">Password</label>
<input class="form-control" data-val="true" data-val-required="The Password field is required." id="inputPassword" name="inputPassword" placeholder="Password" required="required" type="password" />
<div class="checkbox mb-3">
<label>
<input data-val="true" data-val-required="The Remember field is required." id="rememberMe" name="rememberMe" type="checkbox" value="true" /> Remember me
</label>
</div>
<button id="btnLogin" class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
<p class="mt-5 mb-3 text-muted">© 2017-2018</p>
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8Ah5tOyN_3lPrH0DgSEU8vD7Q7JItdizW-mYDc5uamCO3oRTBN-pdo9ZyPgRaHRyovwEGfT5Qhw0UD-rfbIHUJPt4FgUOhM1OkAWC9AtAfPEKkxz7TBfwKfz0EpfxF4DX2DAczujogr__xnIr3vDq3o" /><input name="rememberMe" type="hidden" value="false" /></form>
</body>
</html>
<hr />
<footer>
<p>© 2018 - Chat FIU</p>
</footer>
</div>
<script src="/lib/jquery/dist/jquery.js"></script>
<script src="/lib/bootstrap/dist/js/bootstrap.js"></script>
<script src="/js/site.js?v=BxFAw9RUJ1E4NycpKEjCNDeoSvr4RPHixdBq5wDnkeY"></script>
<script type="text/javascript">
</script>
<script type="text/javascript">
</script>
<script src="/js/NavBarFunction.js"></script>
</body>
The key to solve the problem is in your flow described here:
The correct flow is LoginPage -> Login.js (grabs data and uses Ajax
for a post request.) -> Returns a html page composing of
_Layout.cshtml and /Views/Home/Index.cshtml
This kind of flow implies that you want to redirect into index page (proved by usage of return RedirectToAction("Index", "Account"); in controller action), which AJAX usage in redirection with GET method makes no sense (because AJAX call intended to stay in the same page).
Instead of replacing entire HTML page content using $("html").html(response);, use window.location.href to redirect with specified URL like this:
NavBarFunctions.js
$("#li_btnHome a")[0].click(function (event) {
event.preventDefault();
alert("called click");
var tokenObj = localStorage.getItem("token");
var tokenStr = tokenObj == null ? "what_about_tokenObj_is_null?" : tokenObj.toString();
$.ajax({
type: 'GET',
url: '#Url.Action("Index", "Home")',
beforeSend: function (xhr) {
xhr.setRequestHeader("Authorization", tokenStr);
},
success: function (response) {
// this is just an example, replace action & controller name as you wish
window.location.href = '#Url.Action("ActionName", "ControllerName")';
}
});
});
Login.js
function redirect(redirectUrl) {
$.ajax({
type: 'GET',
contentType: 'application/json; charset=utf-8;',
url: redirectUrl,
success: function (response) {
window.location.href = redirectUrl;
}
});
}
However if you want to render certain portion of the page using partial view, you may use jQuery.html() targeting a placeholder, e.g. <div> tag:
<!-- partial view placeholder -->
<div id="content">...</div>
// ajax callback
$.ajax({
// other settings
.....
success: function (response) {
$('#content').html(response);
},
.....
});
My problem is $http.get instruction --> Without $http.get in the main page I get "random 46" (test ok) but if I insert $http.get I get "random {{ number }}".
How can I fix this?
-server.js
-public
-core.js
-index.html
server.js (node backend)
//restful api
app.get('/api/random', function(req, res) {
res.json({
"text" : "4"
});
});
//app
app.get('*', function(req, res) {
res.sendFile(__dirname + '/public/index.html');
});
core.js (angular frontend)
angular.module("myModule", [])
.controller('myController', function($scope) {
$scope.number = 46;
$http.get('/api/random')
.then(function successCallback(res) {
$scope.number = res.data;
console.log('success');
}, function errorCallback() {
console.log('Error');
});
})
index.html
<html ng-app="myModule">
<head>
<!-- META -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"><!-- Optimize mobile viewport -->
<title>Random number from sa-mp</title>
<!-- SCROLLS -->
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css"><!-- load bootstrap -->
<style>
html { overflow-y:scroll; }
body { padding-top:50px; }
#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="//ajax.googleapis.com/ajax/libs/angularjs/1.6.7/angular.min.js"></script><!-- load angular -->
<script src="core.js"></script>
</head>
<!-- SET THE CONTROLLER AND GET ALL TODOS -->
<body ng-controller="myController">
<div class="container">
<!-- HEADER AND TODO COUNT -->
<div class="jumbotron text-center">
<h1>random <span class="label label-info">{{ number }}</span></h1>
</div>
</div>
</body>
</html>
EDIT:
I tried
res.data
$scope.$apply();
and
res.data.text
$scope.$apply();
and
res.text
$scope.$apply();
but it didn't work.
EDIT 2: RESOLVED
I replaced this
.controller('myController', function($scope) {
with
.controller('myController', function($scope, $http) {
and used this to set data
$scope.number = res.data.text;
Try to use $scope.$apply() at the last line of your callback.
like:
$http.get('/api/random')
.then(function successCallback(res) {
$scope.number = res.data.text;
$scope.$apply();
console.log('success');
}, function errorCallback() {
console.log('Error');
});
If it works. You can know more about that in this article: http://jimhoskins.com/2012/12/17/angularjs-and-apply.html
Also, you should get res.data.text to have the right value on your html. like: $scope.number = res.data.text;
This is simple but my JS is a bit rusty..
I am trying to trigger a get request by pressing a JQuery Mobile element.
I can see the button but failing to do an actual Get Request
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css">
<script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script>
</head>
<body>
<form>
<label for="flip-checkbox-1">Flip toggle switch checkbox:</label>
<p><input type="checkbox" data-role="flipswitch" name="flip-checkbox-1" id="generator_button"></p>
</form>
</body>
<script>
$("p").on("tap",function(){
$.ajax({
'url' : '192.168.8.110:5000/generator_on',
'type' : 'GET',
'success' : function(data) {
if (data == "success") {
alert('request sent!');
}
}
});
</script>
Please, note: in your markup there is a Flip switch of type checkbox, not a button, so I believe you may better check the state of the underlying checkbox instead of stick to a tap event.
Reference: jQuery Mobile Flip switch
Moreover, you it would be nice to provide a JQM page structure to the whole stuff.
Here is an example:
function sendRequest() {
$.ajax({
'url': '192.168.8.110:5000/generator_on',
'type': 'GET',
'success': function(data) {
if (data == "success") {
alert('request sent!');
}
}
});
}
$(document).on("change", "#generator_button", function() {
var state = $("#generator_button").prop("checked");
if (state === true) {
// Flip switch is on
console.log("Request sent.");
//sendRequest(); // uncomment
} else {
// Flip switch is off
//...endpoint _off
}
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<link rel="stylesheet" href="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.css">
<script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
<script src="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.js"></script>
</head>
<body>
<div id="page-one" data-role="page">
<div data-role="header" data-position="fixed">
<h1>Header</h1>
</div>
<div role="main" class="ui-content">
<label for="flip-checkbox-1">Flip toggle switch checkbox:</label>
<input type="checkbox" data-role="flipswitch" name="generator_button" id="generator_button">
</div>
<div data-role="footer" data-position="fixed">
<h1>Footer</h1>
</div>
</div>
</body>
</html>
You are missing }); on last line of your javascript.
Your javascript code should look like this
$("p").on("tap",function(){
$.ajax({
'url' : '192.168.8.110:5000/generator_on',
'type' : 'GET',
'success' : function(data) {
if (data == "success") {
alert('request sent!');
}
}
});
});
Ok, so I had to change the url to: 'http://192.168.8.110:5000/generator_on and tested it on a browser without an adblock I mentioned to make it work!
I am learning angular js right now and have hit another rut. I am trying to make my buttons change the movie ID. I know it is recognizing the click because I had it change some words in the HTML file to test it. I think it isn't talking to my JS file.
I found this during my search http://jsfiddle.net/7Sg6a/. The docs just have an expression inside the parenthesis and this example has parameters. I tried both and a few other but neither worked.
Here is my latest failed attempt. If I could get a nudge in the right direction I would be very grateful.
<!DOCTYPE HTML>
<html lang = "en" ng-app="movies"><!-- lets page use controllers/movies.js-->
<head>
<title>Watch a movie!</title>
<meta charset = "UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<meta name="description" content="">
<meta name="keywords" content="">
<link rel="alternate" type="application/rss+xml" title="RSS 2.0" href="http://www.mysite.com/rss/rss2.xml" />
<link href="css/bootstrap.css" rel="stylesheet" type="text/css">
<link href="css/style.css" rel="stylesheet" type="text/css">
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.0/css/bootstrap-combined.min.css" rel="stylesheet">
<!-- <link href="css/bootstrap-responsive.min.css" rel="stylesheet" type="text/css"> -->
<!-- Preloading scripts? -->
<script src="js/angular.min.js"></script>
<script src="http://code.angularjs.org/1.2.0rc1/angular-route.min.js"></script>
<!--<script src="js/angular-resource.min.js" type="text/javascript"></script>-->
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<!-- <script src="js/bootstrap.js"></script> -->
<script src="controllers/movies.js"></script>
</head>
<body>
<div id="wrapper">
<header>
<div id="logo">
<img src="images/logo.png" alt="Cinema Plus - Movies plus a whole lot more." class="img-responsive">
</div>
</header>
<nav>
<div class='row-fluid'>
<div class="span2"></div>
<button ng-click="nowShowing()" type="button" class="btn btn-primary btn-lg span4 "><h3>NOW PLAYING</h3></button>
<button ng-click="comingSoon()" type="button" class="btn btn-default btn-lg span4 "><h3>COMING FRIDAY</h3></button>
<div class="span2"></div>
</div>
</nav>
<div id='content' class='row-fluid'>
<div class='span8 info'>
<h2 ng-controller = "movieController">{{movies.title}}</h2>
<h2 ng-controller = "movieController">RATED: {{movies.mpaa_rating}}</h2>
<h2 ng-controller = "movieController">{{movies.runtime}} Minutes</h2>
<p ng-controller = "movieController">DESCRIPTION: {{movies.synopsis}}</p>
</div>
<div class='span4 poster'>
<img ng-controller = "movieController" src={{movies.posters.original}} alt={{movies.title}} class="img-responsive">
</div>
</div>
<div>
Note: This theator only plays one movie at a time. film will be hard coded into the app. Would like to see it fed by RSS orsomething in the future.
</div>
</div> <!-- END WRAPPER -->
</body>
</html>
JS
var movies = angular.module('movies', []);
movies.controller('movieController', function ($scope, $http) {
$http.jsonp('http://api.rottentomatoes.com/api/public/v1.0/movies/771303861.json', {
params: {
apikey: 'wq98h8vn4nfnuc3rt2293vru',
callback: 'JSON_CALLBACK'
}
})
.success(function (data) {
$scope.movies = data;
});
});
movies.click('nowShowing', function ($scope){
alert("asdasd");
});
how long until I actually get this and can stop asking stupid questions?
your .click function doesn't belong. You're using Angular like jQuery, and it's more (awesome) than that. You need to put the nowShowing function and such inside your controller:
var movies = angular.module('movies', []);
movies.controller('movieController', function ($scope, $http) {
$http.jsonp('http://api.rottentomatoes.com/api/public/v1.0/movies/771303861.json', {
params: {
apikey: 'secret',
callback: 'JSON_CALLBACK'
}
})
.success(function (data) {
$scope.movies = data;
});
$scope.nowShowing = function(){
//whatever is in here will execute when a user interacts with an element with the ng-click="" directive
}
});
Also, I would highly recommend you create a service for your http requests to your api. You are creating a tightly coupled app with your current approach.
movies.factory('moviedata',function($http){
return
$http.jsonp('http://api.rottentomatoes.com/api/public/v1.0/movies/771303861.json', {
params: {
apikey: 'secret',
callback: 'JSON_CALLBACK'
}
})
})
then 'inject' it in your controller like so:
movies.controller('movieCtrl',function($scope, moviedata){
//resolve returned promise
moviedata.success(function(data){
$scope.data = data;
});
$scope.nowShowing = function($log){
//whatever is in here will execute when a user interacts with an element with the ng-click="" directive
$log.info("nowShowing method fired");
}
})
I am new into web devlopment. I am trying to use select2-bootstrap. It working fine. Just need a css help.
Initial display of widget :
There is an indent between the bars(between Search for a movie and No matches found)
After clicking on the widget it looks fine as shown here and thereafter the dent disappears even on subsequent use.
Can someone suggest how to remove the dent between two bars in the first pic above.
NOTE :
CSS Added : select2.css, select2-bootstrap.css and bootstrap.css
JS Added : bootstrap.js, jquery-1.9.1.js, select2.js
Also please suggest how to avoid the No matches found display immediately after page loads.
Here is the code :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="ISO-8859-1">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Twitter Bootstrap</title>
<link rel="stylesheet" type="text/css" media="screen"
href="css/bootstrap.css" />
<link rel="stylesheet" type="text/css" media="screen"
href="css/select2.css" />
<link rel="stylesheet" type="text/css" media="screen"
href="css/select2-bootstrap.css" />
<script type="text/javascript" src="js/jquery-1.9.1.js"></script>
<script type="text/javascript" src="js/bootstrap.js"></script>
<script type="text/javascript" src="js/select2.js"></script>
<script type="text/javascript">
var contextPath = "<%=request.getContextPath()%>";
$(document)
.ready(
function() {
MultiAjaxAutoComplete('#e6',contextPath + "/getData");
$('#save').click(function() {
alert($('#e6').val());
});
});
</script>
<script type="text/javascript">
function MultiAjaxAutoComplete(element, url) {
$(element).select2({
placeholder : "Search for a movie",
//minimumInputLength : 1,
multiple : true,
ajax : {
url : url,
dataType : 'json',
data : function(term, page) {
return {
q : term,
page_limit : 10,
};
},
results : function(data, page) {
console.log("page = " + page);
return {
results : data.results
};
}
},
formatResult : formatResult,
formatSelection : formatSelection,
initSelection : function(element, callback) {
var data = [];
$(element.val().split(",")).each(function(i) {
var item = this.split(':');
data.push({
id : item[0],
country : item[1]
});
});
callback(data);
}
});
};
function formatResult(movie) {
return '<div>' + movie.country + '</div>';
};
function formatSelection(data) {
return data.country;
};
</script>
</head>
<body style="background-color: #F9F9F6">
<h1>Serach Movies</h1>
<div class="container-fluid">
<div class="row-fluid">
<div class="span9">
<input type='hidden' id="e6" class="span8" />
</div>
<div class="span3">
<button id="save">Save</button>
</div>
</div>
</div>
</body>
</html>