ng-show and $scope.$apply issue - javascript

On the HTML I have an overlay div to show a loading progress which uses the directive ng-show="showLoading". On the template ng-click I call the controller searchRequest method. This method updates showLoading to true just before making the http request.
If I do it this way the loading doesn't show, if I use the $scope.$apply to update the variable then I got the $apply already in progress error message. What is going on? How should I do this?
This is the index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<title></title>
<link href="lib/ionic/css/ionic.css" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">
<!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above
<link href="css/ionic.app.css" rel="stylesheet">
-->
<!-- ionic/angularjs js -->
<script src="lib/ionic/js/ionic.bundle.js"></script>
<!-- cordova script (this will be a 404 during development) -->
<script src="cordova.js"></script>
<script src="js/angular-route.js" ></script>
<!-- your app's js -->
<script src="js/searchController.js"></script>
<script src="js/app.js"></script>
</head>
<body ng-app="myApp" ng-init="showLoading = false">
<div id="overlay" ng-show="showLoading">
<img id="loading" src="img/ajax-spinner.gif" />
</div>
<div ng-view></div>
</body>
</html>
The template:
<div ng-controller="searchController as searchController">
<ion-header-bar class="bar-stable">
<h1 class="title">Movie Searcher</h1>
</ion-header-bar>
<ion-content>
<label class="item item-input">
<span class="input-label">Title</span>
<input style="border-style: solid;border-width: 1px;" type="text" ng-model="searchController.searchString" required>
</label>
<button class="btn" ng-click="searchController.search()">Search</button>
{{response}}
</ion-content>
</div>
And the controller:
this.searchRequest = function(url) {
$scope.showLoading = true;
$http.get(url).success(function(data) {
$scope.showLoading = false;
//console.log("Success: " + JSON.stringify(data));
$scope.response = JSON.stringify(data);
for (i=0; i<data.length; i++) {
var movie = data[i];
//console.log("Movie: " + movie);
var genres = '';
for (j=0; j<movie.genres.length; j++) {
genres += movie.genres[j];
if (j < movie.genres.length - 1) {
genres += ', ';
}
}
console.log("Title: " + movie.title);
console.log("Plot: " + movie.simplePlot);
console.log("genres: " + genres);
}
})
.error(function(data, status, headers, config) {
$scope.showLoading = false;
$scope.response = "Error: " + status;
})};

Your Overlay div does not have the data context of the right controller.
When you specify the ng-controller directive, you are telling angular to use that specific controller as its current scope.
<div ng-controller="searchController as searchController">
Whereas for your body section here, you did not specify the right controller. So, angular doesn't know where showloading property is coming from.
<body ng-app="myApp" ng-init="showLoading = false">
<div id="overlay" ng-show="showLoading">
<img id="loading" src="img/ajax-spinner.gif" />
</div>
<div ng-view></div>
</body>
Either move the overlay div into the div which has the controller as context or try using $rootScope instead.

Probably the easiest way to force a digest cycle without having to worry about the phase is to wrap the var change call inside a $timeout function:
$timeout(function() {
$scope.showLoading = true;
}, 0);
$http.get(url).success(function(data) {
...
Of course, don't forget to inject $timeout as a dependency in your controller.

Related

Angularjs fails to dynamic change image src

Hello i'm building an application where i want to dynamically change the source of an image in order to force reload it . The problem is that in order of this i only get a broken image on the browser. Instead , if a run the function manually by a button it runs perfect .
HTML document
<!DOCTYPE html>
<html lang="en" ng-app='cameraApp'>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Node JS Camera</title>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css">
<script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular.min.js"></script>
<script src='https://code.angularjs.org/1.4.4/angular-sanitize.min.js'></script>
<script src="cameraApp.js"></script>
</head>
<body>
<div class="container-fluid">
<div class="jumbotron">
<h1>Welcome to NodeJS Camera v1</h1>
</div>
<div ng-controller="HomeController">
<div class="cameraControl col-md-5">
<p>Here is the camera control</p>
<button class="btn btn-default" ng-click="getSnapshot()">Snapshot</button>
<button class="btn btn-info" ng-click="intervalFunction()">Start Feed</button>
</div>
<div class="lifeFeed col-md-7">
<p>Here is the live feed</p>
<p><button class="btn btn-default" ng-click="readSnapshot()">Snapshot Read</button></p>
<img width='600' height='600' ng-src="{{snapshot}}" alt="SnapShot taken">
</div>
</div>
</div>
</body>
</html>
cameraApp.js
var cameraApp = angular.module('cameraApp',[]);
cameraApp.controller('HomeController', function($scope,$http,$timeout) {
function updateImage() {
var img = 'snapshots/camera.jpg'+ '?decache=' + Math.random();
console.log('Snapshot Loaded');
$scope.snapshot = img;
};
$scope.readSnapshot = updateImage;
$scope.getSnapshot = function() {
$http.get('/api/getSnapshot')
.then(function(response) {
// this callback will be called asynchronously
// when the response is available
console.log('Snapshot captured');
$scope.readSnapshot();
}, function(response) {
console.log('Error in capturing...');
});
}
$scope.intervalFunction = function() {
$timeout(function() {
$scope.getSnapshot();
$scope.intervalFunction();
}, 2000);
};
// Kick off the interval
$scope.intervalFunction();
});
There are two solutions I've used for this in the past.
1) Use an ng-if/ng-show on your img tag. This will prevent the broken image from displaying.
<img ng-if='snapshot'>
2) Set a default image that will load and then be replaced once the other images load.
$scope.snapshot = 'snapshots/default.png';

Impress.js and AngularJS Controller

I am running an AngularJS application/controller. My goal is to initialize and use the impress.js library on a page that is being dynamically loaded into my main home page. However, when I try to initialize the library, the page does not load. Attached is a snippet of the controller and html file.
NOTE: When I print the impress() object to the console, it is not null, and has the required functions. It is my suspicion that the impress() object is not hooking up to the page correctly.
Controller:
'use strict';
// Create the angular module
var cmodule = angular.module('coverage', ['ngRoute'])
// Create the coverage controller
cmodule.controller('coverageController', function($scope) {
console.log("Entering controller");
function require(script) {
$.ajax({
url: script,
dataType: "script",
async: true, // <-- This is the key
success: function () {
console.log(impress());
impress().init();
},
error: function () {
throw new Error("Could not load script " + script);
}
});
}
console.log("About to require");
angular.element(document).ready(function () {
require("/content/libraries/impress.js");
});
});
HTML File:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<meta name="viewport" content="width=1024" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<title>My Coverage</title>
<link rel="stylesheet" href="/content/styles/team1.css">
</head>
<body class="impress-not-supported">
<!--
For example this fallback message is only visible when there is `impress-not-supported` class on body.
-->
<div class="fallback-message">
<p>Your browser <b>doesn't support the features required</b> by impress.js, so you are presented with a simplified version of this presentation.</p>
<p>For the best experience please use the latest <b>Chrome</b>, <b>Safari</b> or <b>Firefox</b> browser.</p>
</div>
<!-- Now the fun begins -->
<div id="impress">
<!-- The background image -->
<div class="present" data-x="0" data-y="0">
<!-- Place Image here -->
</div>
<!-- Example content -->
<div id="url-ident" class="step" data-x="0" data-y="0">
<q>Ready to view your coverage?</q>
</div>
<!-- Example content -->
<div id="step1" class="step" data-x="500" data-y="0">
<p>Questions start here!</p>
</div>
</div> <!-- /div impress -->
<script type="text/javascript" src="/content/libraries/impress.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
<!--script type="text/javascript">impress().init();</script-->
</body>
</html>
This problem was fixed by using the jmpress.js library instead, found here.

angular/ionic - model does not update $scope in controller

I am a newb with angularjs and I am trying something that I believe should be very simple ... but turns out I am not figuring it out.
I have a $scope variable that I want to double bind (using ng-model) to a textarea. I was able to make it work on js fiddle websites but now on my code. I have tried to strip everything down to just a few lines and it still doesn't work, the controller is never updated.
this is my code:
js/main.js
var app=angular
.module('noclu', ['ionic', 'app.controllers'])
.config(function ($stateProvider, $urlRouterProvider){
$stateProvider
.state('menu.main', {
url: "/main",
views: {
'menuContent': {
templateUrl: 'templates/main.html',
controller: 'MainCtrl'
}
}
});
$urlRouterProvider.otherwise("/menu/main");
});
js/controller.js
angular
.module('app.controllers', [])
.controller('MainCtrl', function ($scope){
$scope.src='---';
$scope.get_feeds=function(){
//seems like that here "this" is actually the textarea ??
//$scope.src is always whatever has been set in the controller
console.log('this:'+this.src); //this output whatever I enter in the textarea
console.log('scope:'+$scope.src); //this always output '---'
};
});
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<link rel="icon" type="image/png" href="favicon.png">
<title>NoClu</title>
<link href="lib/ionic/css/ionic.css" rel="stylesheet">
<!-- ionic/angularjs js -->
<script src="lib/ionic/js/ionic.bundle.js"></script>
<!-- cordova script (this will be a 404 during development) -->
<script src="cordova.js"></script>
<!-- your app's js -->
<script src="js/main.js"></script>
<script src="js/controllers.js"></script>
</head>
<body ng-app="noclu">
<ion-nav-view></ion-nav-view>
</body>
</html>
template/main.html
<ion-view view-title="NoClu" >
<ion-content class="padding" id="src-wrapper-center">
<div ng-class="vertical_center">
<div id="src-wrapper">
<div>
<div class="padding src-title">What are you in the mood for ?</div>
<div class="item" id="src-txt-wrapper">
<textarea id="src" ng-model="src"></textarea>
</div>
<button id="search" class="button button-block button-large button-balanced" ng-click="get_feeds()" >
Let's eat
</button>
</div>
</div>
</div>
</ion-content>
</ion-view>
UPDATE - I made it work, but why ?
I made it work by changing $scope.src='---'; to $scope.src={body:'---'}; and then changing the ng-modal to src.body. but.. WHY did not work the other way as it works for boolean?
Using directly $scope. is not a good practice in angularJS. There are various post of it, more concernign $scope inheritence.
For exemple : http://learnwebtutorials.com/why-ng-model-value-should-contain-a-dot
Therefore, your need to change your model like that :
$scope.myModel = {};
$scope.myModel.src = "---"
And your html to bind to myModel.src

How to send form data from ionic app to parse.com MBaaS using REST API

I'm extremely new to Ionic/Angular (Started today itself out of necessity),
Taking help of tutorials as well as documentations,
I had been creating a demo/test app that submits data to Parse.com MBaaS service.
But something somewhere is going wrong, clueless on how to go add the three form fields
Details: the App name is TestApp
Class/Table name is data
there are three columns, fname, lname and uname (for firstname lastname and username)
Here's the code I've been following. Any help would be deeply obliged.
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<title></title>
<link href="lib/ionic/css/ionic.css" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">
<!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above
<link href="css/ionic.app.css" rel="stylesheet">
-->
<!-- ionic/angularjs js -->
<script src="lib/ionic/js/ionic.bundle.js"></script>
<!-- cordova script (this will be a 404 during development) -->
<script src="cordova.js"></script>
<!-- your app's js -->
<script src="js/app.js"></script>
</head>
<body ng-app="starter">
<div>
<div>
<ion-nav-bar class="bar-stable">
<ion-nav-back-button class="button-icon icon ion-ios7-arrow-back">Back</ion-nav-back-button>
</ion-nav-bar>
<ion-nav-view></ion-nav-view>
</div>
</div>
<!-- Center content -->
<ion-view title="Add Data">
<ion-content padding="true" scroll="false" class="has-header">
<div class="spacer" style="height: 100px;"></div>
<form ng-controller="defaultCtrl">
<ion-list>
<label class="item item-input">
<span class="input-label">First Name</span>
<input type="text" placeholder="First Name here" name="fname" ng-model="starter.fname">
</label>
<label class="item item-input">
<span class="input-label">Last Name</span>
<input type="text" placeholder="Surname Here" name="lname" ng-model="starter.lname">
</label>
<label class="item item-input">
<span class="input-label">Username</span>
<input type="text" placeholder="Username here" name="uname" ng-model="starter.uname">
</label>
</ion-list>
<button class="button button-calm button-block" type='submit' ng-click="create(starter)">Add data</button>
</form>
</ion-content>
</ion-view>
<script type="text/javascript">
angular.module('starter',['ionic']).factory('starter',['$http','PARSE_CREDENTIALS',function($http,PARSE_CREDENTIALS){
return {
create:function(data){
return $http.post('https://api.parse.com/1/classes/data',data,{
headers:{
'X-Parse-Application-Id': PARSE_CREDENTIALS.APP_ID,
'X-Parse-REST-API-Key':PARSE_CREDENTIALS.REST_API_KEY,
'Content-Type':'application/json'
}
});
}
}
}]).value('PARSE_CREDENTIALS',{
APP_ID: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
REST_API_KEY:'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
});
angular.module('starter', ['ionic'])
.controller("defaultCtrl", function ($scope) {
$scope.starter = {};
$scope.create=function(){
starter.create({fname:$scope.starter.fname}).success(function(data){
});
});
</script>
</body>
</html>
Set the authentication headers
PARSE_HEADER_CREDENTIALS = {
"x-parse-application-id": "PARSE-APPLICATION-ID",
"x-parse-rest-api-key": "PARSE-REST-API-KEY"
};
code
addObject: function (_params) {
// for POST, we only need to set the authentication header
var settings = {
headers: PARSE_HEADER_CREDENTIALS,
};
// for POST, we need to specify data to add, AND convert it to
// a string before passing it in as seperate parameter data
var dataObject = {
"name": _params.name,
"room": _params.room,
};
var dataObjectString = JSON.stringify(dataObject);
// $http returns a promise, which has a then function
return $http.post(baseURL + 'classes/stuff', dataObjectString, settings)
.then(function (response) {
// In the response resp.data contains the result
// check the console to see all of the data returned
console.log('addObject', response);
return response.data;
});
},
complete example posted in project here:
https://github.com/aaronksaunders/info-rest-api-ionic-sample

Restify server with Angular, not working

I am learning to use Restify to build a Restful API and work with Angular.
Below is my structure:
Project
page_admin
core.js
index.html
node_modules
restify
mongojs
server.js
I had set up server and implemented several API calls.
Below news API return a list of JSON data in browser:
`http://localhost:8080/news`
`[{"_id":"53b2a2c3373551813dfe8b91","title":"first","subtitle":"foobar","textbody":"","postedOn":"2014-07-01T12:00:03.215Z"},{"_id":"53b2a122373551813dfe8b8e","title":"my second","subtitle":"my second title","textbody":"node is cool","postedOn":"2014-07-01T11:53:06.389Z"},{"_id":"53b2a0cd373551813dfe8b8d","title":"delay announcement","subtitle":"sub ","textbody":"I am the text body","postedOn":"2014-07-01T11:51:41.678Z"}]`
here is my code to handle client side route:
server.get('/', restify.serveStatic({
'directory': './page_admin',
'default': 'index.html'
}));
My index.html is simple:
<!-- index.html -->
<!doctype html>
<!-- ASSIGN OUR ANGULAR MODULE -->
<html ng-app="bluesky">
<head>
<!-- META -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"><!-- Optimize mobile viewport -->
<title>My test app</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.0.8/angular.min.js"></script><!-- load angular -->
<script src="core.js"></script>
</head>
<!-- SET THE CONTROLLER AND GET ALL TODOS -->
<body ng-controller="mainController">
<div class="container">
<!-- HEADER AND TODO COUNT -->
<div class="jumbotron text-center">
<h1>My example is working <span class="label label-info">{{ news.length }}</span></h1>
</div>
<!-- TODO LIST -->
<div id="todo-list" class="row">
<div class="col-sm-4 col-sm-offset-4">
<!-- LOOP OVER THE TODOS IN $scope.todos -->
<div class="checkbox" ng-repeat="new in news">
<label>
<input type="checkbox" ng-click="deleteTodo(new._id)"> {{ new.subtitle }}
</label>
</div>
</div>
</div>
</div>
</body>
</html>
core.js is like this:
var bluesky = angular.module('bluesky', []);
function mainController($scope, $http) {
$scope.formData = {};
$http.get('/news')
.success(function(data) {
$scope.news = data;
console.log(data);
})
.error(function(data) {
console.log('Error: ' + data);
});
}
when I try to navigate to: http://localhost:8080
I got my index page but it shows me:
'My example is working {{ news.length }}
and in console, I saw following error:
GET `http://localhost:8080/core.js` 404 (Not Found)
localhost/:24
Uncaught Error: No module: bluesky
angular.min.js:18
what I just missed so that the angular is not retrieving the data?
=============================================================
upate
if I directly include core.js put code inside , then it works.
but, how to solve this 404 not found issue? just don't want to include all js files in the index page.
As far as my knowledge about angular js, controller is not defined in your module. So instead of using function mainController($scope, $http) {
....
}
you should define controller inside the module bluesky as follows
bluesky.controller("mainController",function($scope,$http)
{
....
});

Categories

Resources