how to use $scope inside .on click event? - javascript

I'm very new to Angular js and am testing a few functions with a simple data-parser project (Plunkr). Right now, I'm having trouble accessing $scope variable within a jQuery on click event. I would like to keep some elements hidden until an image is clicked. While I can set ng-hide to true within the controller, $scope does not appear to work inside an on click handler. Please help.
zodiac.html
<!DOCTYPE html>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body>
<div id="container" ng-app="myApp" ng-controller="myCtrl">
<div>
<h1>What Animal Are You?</h1>
<div id="selectPicture"></div>
</div>
<div id="zodiac" ng-hide="disappear">
<h1>Your Zodiac</h1>
<div id="your-zodiac">
</div>
<br>
<h1>Avoid these Animals</h1>
<div id="hateDiv">
</div>
<br>
<h1>These Are Your Besties</h1>
<div id="loveDiv">
</div>
</div>
<script src="scripts.js"></script>
</div>
</body>
scripts.js
function d(c) {
console.log(c)
}
var app = angular.module('myApp', [])
app.controller('myCtrl', function($scope, $http) {
$http.get('zodiac.json').success(function(data) {
$scope.disappear = true //WORKS HERE
$scope.animalsData = data
angular.forEach($scope.animalsData, function(item) {
$('#selectPicture').prepend('<img src="' + item.picture + '" alt="' + item.animal + '">')
})
$('#selectPicture').on('click', 'img', function($scope) {
$scope.disappear = false //DOES NOT WORK HERE
$('#zodiac div').empty();
findZodiac(this.alt, "#your-zodiac", true);
})
function findZodiac(animal, e, test) {
angular.forEach($scope.animalsData, function(item) {
if (item.animal == animal) { //look for the right object 'item', when found, get the image
//item.picture
$(e).prepend('<img src="' + item.picture + '">')
if (test == true) {
loveHate(item.hate, "#hateDiv")
loveHate(item.love, "#loveDiv")
}
return
}
})
}
function loveHate(array, e) {
angular.forEach(array, function(value) { //loops through an array, get each animal
findZodiac(value, e, false)
})
}
});
})

In my opinion you should not do DOM manipulation directly when using AngularJS. Use the directives provided by AngularJS instead. Here are the template and controller code if you do so -
zodiac.html
<!DOCTYPE html>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body>
<div id="container" ng-app="myApp" ng-controller="myCtrl">
<div>
<h1>What Animal Are You?</h1>
<div id="selectPicture">
<img ng-repeat="animal in animalsData"
ng-src="{{animal.picture}}"
alt="{{animal.animal}}"
ng-click="disappear=false; findZodiac(animal)" />
</div>
</div>
<div id="zodiac" ng-hide="disappear">
<h1>Your Zodiac</h1>
<div id="your-zodiac">
<img ng-src="{{selectedAnimal.picture}}" alt="{{selectedAnimal.animal}}" />
</div>
<br>
<h1>Avoid these Animals</h1>
<div id="hateDiv">
<img ng-repeat="animal in selectedAnimal.hate"
ng-src="{{animal.picture}}"
alt="{{animal.animal}}" />
</div>
<br>
<h1>These Are Your Besties</h1>
<div id="loveDiv">
<img ng-repeat="animal in selectedAnimal.love"
ng-src="{{animal.picture}}"
alt="{{animal.animal}}" />
</div>
</div>
<script src="scripts.js"></script>
</div>
</body>
scripts.js
var app = angular.module('myApp', [])
app.controller('myCtrl', function($scope, $http) {
$scope.animalsData = [];
$scope.selectedAnimal = {};
$scope.disappear = true;
$scope.findZodiac = function(animal) {
$scope.selectedAnimal = animal;
};
$http.get('zodiac.json').success(function(data) {
$scope.animalsData = data;
});
});

In AngularJS $scope is a global variable for your controller, You don't need to pass it like this. directly use it as
$('#selectPicture').on('click','img',function(){
$scope.disappear=false;//this will work
$('#zodiac div').empty();
findZodiac(this.alt,"#your-zodiac",true);
})

check this corrected version
scope object only available in angular world.

Related

Why sometimes doesn't ng-init trigger $watch listener?

I execute the follow code in my app and sometimes ng-init doesn't trigger $watch. Any ideas?
HTML
<div ng-controller="MyCtrl">
<p ng-init="stages = 'coco'">{{x}}</p>
</div>
Controller
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.$watch("stages", function() {
alert($scope.stages);
});
}
No it does, according to your code you have not added ng-app anywhere.
DEMO
var myApp = angular.module('myApp',[]);
myApp.controller('MyCtrl',function($scope){
$scope.$watch("stages", function() {
alert($scope.stages);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<p ng-init="stages = 'coco'">{{x}}</p>
</div>

Angular Load Json Error

I'm an Angular beginner.
I want to load a json on load, this works well
but if I make a change to an input field, I get an error message.
Error: $rootScope:infdig Infinite $digest Loop
Thanks
My HTML
<body ng-app="myApp" ng-controller="mainCtrl">
<div id="wrapper">
<header style="height:50px;"> </header>
<div class="container">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<script src="js/controller.js"></script>
<section>
<div class="col-md-4">
<label for="words">Wörter</label>
<input ng-model="words" id="words" type="number" name="words" placeholder="Wörter" min="10" max="10000" value="{{words}}" step="10">
</div>
<p>{{words}}</p>
<div id="view" class="col-md-6">
<ul ng-controller="loadContent">
<li ng-repeat="content in contents | orderBy:random">{{content.text}}</li>
</ul>
</div>
</section>
</div>
</div>
My javascript
var app = angular.module('myApp', []);
app.controller('mainCtrl', function ($scope, $http) {
$scope.words = 40;
$scope.letterLimit = 400;
});
app.controller('loadContent', function ($scope, $http) {
$scope.random = function () {
return 0.5 - Math.random();
}
$scope.loadContent = function() {
var def = $http.get('data.json').success(function(data) {
$scope.contents = data;
});
}
$scope.loadContent();
});
My json
[
{"text": "Lorem ipsum1", "date" : true},
{"text": "Lorem ipsum2", "data" : true},
{"text": "Lorem ipsum3", "data" : true}
]
I think that angular is continuously disgesting your controller as soon as you interact with the view, and is therefore executing $scope.loadContent(); at the bottom of your controller repeatedly.
I assume you only wish for this to fire once? If so, remove the function call from your controller and modify your view as below.
<body ng-app="myApp" ng-controller="mainCtrl" ng-init="loadContent">
With this, $scope.loadContent is only called once. if you wish to call it another way, or multiple times, please specify in your question.

Use AngularJS $http.get to repeatedly request JSON array on scrolling

Below is a snippet using AngularJS to get the JSON response.
On scrolling to the bottom of the page, I need to request repeatedly till the JSON array list is empty.
<section>
<div style="padding-top:60px" infinite-scroll="myPagingFunction()" infinite-scroll-distance="3" ng-app="myApp" ng-controller="myCtrl">
<div ng-repeat="news in newsList">
<div class="col-lg-3 col-md-4 col-sm-6" style="">
<div class="thumbnail">
<img src="{{news.coverUrl}}" class="img-responsive" alt="{{news.name}}"/>
<div class="caption">
<h4>{{news.name}}</h4>
</div>
</div>
</div>
<div class="visible-lg clearfix" ng-if="($index+1)%4 == 0"></div>
<div class="visible-md clearfix" ng-if="($index+1)%3 == 0"></div>
<div class="visible-sm clearfix" ng-if="($index+1)%2 == 0"></div>
</div>
</div>
</section>
<script src="js/jquery.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script src="js/ng-infinite-scroll.min.js"></script>
<script>
var offset = 0
var maxCount = 20
var app = angular.module('myApp', ['infinite-scroll']);
function myPagingFunction(){
app.controller('myCtrl', function($scope, $http) {
$http.get("news.json").then(function(response) {
$scope.newsList = response.data;
});
});
}
myPagingFunction();
</script>
<script src="js/bootstrap.min.js"></script>
Kindly help me in solving this.
Using jQuery + angular is not good
You must use angular way instead, and write some directives or listeners in run phase, but here's a better approach - use `ngInfiniteScroll plugin
You can simply use infinite Scroll services to easily achieve this ,
<ANY infinite-scroll='{expression}'
[infinite-scroll-distance='{number}']
[infinite-scroll-disabled='{boolean}']
[infinite-scroll-immediate-check='{boolean}']
[infinite-scroll-listen-for-event='{string}']>
Add ng-infinite scroll module in your application
for more info refer this [Documentation]:(https://sroze.github.io/ngInfiniteScroll)
You can use this simple directive and enjoy:
app.directive("scroll",['$window', function ($window) {
return function (scope, element, attrs) {
angular.element($window).bind("scroll", function () {
if (document.body.scrollHeight - $window.scrollY < 890) {
scope.$apply(function () {
scope.myPagingFunction();
});
}
});
};
}]);
and you can use this code for your situation
<section>
<div style="padding-top:60px" scroll ng-app="myApp" ng-controller="myCtrl">
<div ng-repeat="news in newsList">
<div class="col-lg-3 col-md-4 col-sm-6" style="">
<div class="thumbnail">
<img src="{{news.coverUrl}}" class="img-responsive" alt="{{news.name}}"/>
<div class="caption">
<h4>{{news.name}}</h4>
</div>
</div>
</div>
<div class="visible-lg clearfix" ng-if="($index+1)%4 == 0"></div>
<div class="visible-md clearfix" ng-if="($index+1)%3 == 0"></div>
<div class="visible-sm clearfix" ng-if="($index+1)%2 == 0"></div>
</div>
</div>
</section>
<script src="js/jquery.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script src="js/ng-infinite-scroll.min.js"></script>
<script>
var offset = 0
var maxCount = 20
var app = angular.module('myApp', ['infinite-scroll']);
app.controller('myCtrl', function ($scope, $http) {
$scope.myPagingFunction= function() {
$http.get("news.json").then(function (response) {
$scope.newsList = response.data;
});
}
});
app.directive("scroll",['$window', function ($window) {
return function (scope, element, attrs) {
angular.element($window).bind("scroll", function () {
if (document.body.scrollHeight - $window.scrollY < 890) {
scope.$apply(function () {
scope.myPagingFunction();
});
}
});
};
}]);
</script>
<script src="js/bootstrap.min.js"></script>

How to return html5 audio/video as output inside angular filter

I have this code which filter out some special text and returns audio element but it does'nt work only with html5 audio/video element how can I fix it(it works with all other html tage for eg: h1 tag etc)?
angular.module('demo', ['ngSanitize']);
angular.module('demo').filter('toAudSrc',function(){
return function (text) {
regex = /^\*\*\*!(.*)!\*\*\*$/;
if(regex.test(text))
return text.replace(/^\*\*\*!(.*)!\*\*\*$/,'<audio width="200" controls preload>'+
'<source src="http://www.w3schools.com/html/horse.ogg" type="audio/mp3">'+
'</audio>');
else
return text;
}
});
angular.module('demo').controller('MyController', ['$scope', function($scope) {
$scope.greeting = '***!Hola!***';
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-sanitize/1.5.5/angular-sanitize.min.js"></script>
<div ng-app='demo'>
<div ng-controller="MyController">
<h3 ng-bind-html="greeting | toAudSrc"></h3>
</div>
</div>
Okay I read the docs again and found this solution, for anyone who has similar problem
angular.module('demo', ['ngSanitize']);
angular.module('demo').filter('toAudSrc',function($sce){
return function (text) {
regex = /^\*\*\*!(.*)!\*\*\*$/;
if(regex.test(text))
return $sce.trustAsHtml(text.replace(/^\*\*\*!(.*)!\*\*\*$/,'<audio width="200" controls preload>'+
'<source src="http://www.w3schools.com/html/horse.ogg" type="audio/mp3">'+
'</audio>'));
else
return text;
}
});
angular.module('demo').controller('MyController', ['$scope', function($scope) {
$scope.greeting = '***!Hola!***';
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-sanitize/1.5.5/angular-sanitize.min.js"></script>
<div ng-app='demo'>
<div ng-controller="MyController">
<h3 ng-bind-html="greeting | toAudSrc"></h3>
</div>
</div>

materialbox Materializecss works only after typing initialization jQuery in console

I have used '.materialboxed' in my webpage, but the initialization in script doesn't work, I have to manually type $('.materialboxed').materialbox(); in console for it to work.
Html (ui-view in angular route)
<div class="row">
<div class="card-panel col l12" style="height: 750px;">
<img class="col l5 materialboxed" height="500px" id="poster"
ng-src="https://image.tmdb.org/t/p/original{{poster_path}}"/>
<div class="col l7">
<div class="row">
<a class="col l10" style="float:left;text-align: left;" ng-href="{{homepage}}">
<h3 class="title" ng-bind="original_title"></h3>
</a>
<a ng-href="http://www.imdb.com/title/{{imdb_link}}"
style="float:right;text-align: right; margin-top: 29px;"
class="imdb-link col l2" title="IMDb"><i class="icon-imdb"></i></a>
</div>
<div class="row"><p ng-bind="overview"></p>
<span class="right" ng-bind="release_date"></span>
<h5>Genres</h5>
<p ng-bind="genre"></p>
<h5>Production Companies</h5>
<p ng-bind="names">
</p>
<h5>Voting</h5>
<p ng-bind="vote_average"></p></div>
</div>
</div>
</div>
See the in 3rd line.
index.html
//rest code
<main ui-view></main>
</div>
<script src="js/angular_min.js"></script>
<script src="js/angular-touch.min.js"></script>
<script src="js/angular-ui-router.min.js"></script>
<script src="js/angucomplete-alt.js"></script>
<script src="appRoute.js"></script>
<script src="controller/MovieController.js"></script>
<script src="controller/LoginController.js"></script>
<script src="controller/RegisterController.js"></script>
<script src="controller/TvController.js"></script>
<script src="controller/LoggedInController.js"></script>
<script src="controller/TopMovieController.js"></script>
<script src="app-services/DetailsService.js"></script>
<script src="js/jquery-1.11.3.min.js"></script>
<script src="js/materialize.min.js"></script>
<script>
$(document).ready(function () {
$('.materialboxed').materialbox();
$('.button-collapse').sideNav({
menuWidth: 300,
edge: 'left',
closeOnClick: true
}
);
$('.modal-trigger').leanModal();
$("#movie").click(function () {
window.location.href = window.location.pathname + "#/movie";
});
$("#tv").click(function () {
window.location.href = window.location.pathname + "#/tv";
});
});
</script>
</body>
Even after initializing the materialboxed, it doesn't work. It works only after typing $('.materialboxed').materialbox(); in console manually.
Help me figure this out. Thanks
You shouldn't use $(document).ready in Angular. In fact you should try to use as little jQuery as possible, but if you need to, then you should create a directive that allows you to initialize the function after they render.
var app = angular.module('myApp');
app.directive('onLastRepeat', function() {
return function(scope, element, attrs) {
if (scope.$last)
setTimeout(function() {
scope.$emit('onRepeatLast', element, attrs);
}, 1);
};
});
app.controller('MoviesController', function($scope) {
$scope.$on('onRepeatLast', function(scope, element, attrs) {
$('.materialboxed').materialbox();
});
}
Now you can apply this to your HTML:
<ul>
<!-- this is just an example with the added directive -->
<li ng-repeat="movie in movies" on-last-repeat>
<img ng-src="{{imageObjectHere}}" class="materialboxed">
</li>
</ul>
Since you added this new directive in there, the $('.materialboxed').materialbox(); should fire after the repeat is done

Categories