How to access parent controller data inside a loop - angularjs

I have a problem with angularJS.
I have a controller that execute a loop. For every element in the list I display all the informations.
Inside every loop, I added another controller (I guess is not a best practice already).
From the inner controller i want to access data from the outer controller.
Now, I don't mind doing this by assigning metadata on the html code, or by javascript code in the controller.
Here what I have done:
<div ng-controller="PostListCtrl">
<div ng-repeat="e in posts" class="col-lg-3 col-md-4 col-sm-12 col-xs-12">
<div class="galleryElement effect6">
<div class="innerGalleryElement">
<div>
<img class="img-responsive" src="" /><!--{{e.Post.cover}}-->
</div>
<div class="lowerBarHolder">
<div class="float-left avatar">
<div class="shadow">
<img src="{{e.Post.author_avatar}} " />
</div>
</div>
<div class="float-left description">
{{e.Post.title}} <br />
{{e.Post.author}}
</div>
<div ng-controller="PostHeart" class="likeHolder" ng-init="isActive={{e.Post.isActive}}">
<button ng-click="toggleActive($index)"
ng-class="{true: 'loveButtonActive', false: 'loveButton'}[isActive]"
class="">❤</button>
</div>
</div>
</div>
</div>
</div>
This code: ng-init="isActive={{e.Post.isActive}} doesn't work as supposed.
I also tried to assign with data-myData="{{e.Post.isActive}} but at runtime when i tried to access myData from the controller it does access the string {{e.Post.isActive}} instead of accessing the replacement of that placeholder.
Any idea?

Create a directive:
yourModule.directive('postHeart', function() {
return {
restrict: 'E',
scope: {
'e': '=',
'index': '='
},
controller: function($scope) {
var isActive = $scope.e.Post.isActive;
$scope.btnClass = isActive ? 'loveButtonActive' : 'loveButton';
$scope.toggleActive = function(index) {
var postId = $scope.e.Post.id; // access data from the parent controller
// ...
};
},
template: "<button ng-click=\"toggleActive(index)\" ng-class=\"btnClass\">❤</button>"
};
});
Then use it in template:
<div ng-controller="PostListCtrl">
<div ng-repeat="e in posts" class="col-lg-3 col-md-4 col-sm-12 col-xs-12">
<div class="galleryElement effect6">
<div class="innerGalleryElement">
<div>
<img class="img-responsive" src="" /><!--{{e.Post.cover}}-->
</div>
<div class="lowerBarHolder">
<div class="float-left avatar">
<div class="shadow">
<img src="{{e.Post.author_avatar}} " />
</div>
</div>
<div class="float-left description">
{{e.Post.title}} <br />
{{e.Post.author}}
</div>
<post-heart e="e" index="$index" class="likeHolder"></post-heart>
</div>
</div>
</div>
</div>

Related

angular js data now showing in front end

the data is showing in the log but its now showing in my page.i wanted to load the data . what is the problem?
function AppController($scope, TestFactory) {
/* console.log("AppController is now available.");*/
$scope.testdata= [];
TestFactory.getData().then(function(response) {
$scope.testdata = response.data;
console.log("Data:", $scope.testdata);
})
}
<ion-slide-page ng-repeat="event in testdata">
<div class="now-viewport">
<div class="event-image">
</div>
<div class="event-placeholder">
<div class="event-title">{{ event.message}}</div>
<div class="event-details">
</div>
</div>
</div>
</ion-slide-page>
try the following code below
<ion-slide-page ng-repeat="event in testdata.message">
<div class="now-viewport">
<div class="event-image">
<div class="event-placeholder">
<div class="event-title">{{event}}</div>
<div class="event-details"></div>
</div>
</div>
</div>
</ion-slide-page>
Your response is an object where message is an array of strings, try as follows,
<ion-slide-page ng-repeat="event in testdata.message">
<div class="now-viewport">
<div class="event-image">
<div class="event-placeholder">
<div class="event-title">{{event}}</div>
<div class="event-details"></div>
</div>
</div>
</div>
</ion-slide-page>

Edit input after getting all data angular

I have function in my controller where I retrieve all my data from database (id,name,surname,emai,review):
function loadAll() {
UniversalService.GetAll()
.then(function (a) {
$scope.all=a;
});
}
then I print it like this in html:
<div class="row comment-table" ng-repeat="item in all ">
<div class="col-md-1">
<img ng-src="http://www.gravatar.com/avatar/{{hash[$index]}}" alt="Description" />
</div>
<div class="col-md-9">
<p>Review posted by: {{item.name}}</p>
<p>{{item.review}}</p>
<span uib-rating ng-model="rate" max=5 on-hover="hoveringOver(value)" on-leave="overStar = null" titles="['one','two','three']" aria-labelledby="default-rating"></span>
<span class="label" ng-class="{'label-warning': percent<30, 'label-info': percent>=30 && percent<70, 'label-success': percent>=70}" ng-show="overStar && !isReadonly">{{percent}}%</span>
</div>
</div>
Now, I added edit and delete buttons for each review. But I am not sure how to actually edit specific review beause I need to have these values inside inputs and how to delete them. Is it possible when I printed my values with loadAll() ?
By using the $index.
In you html:
<div class="row comment-table" ng-repeat="item in all ">
<div class="col-md-1">
<img ng-src="http://www.gravatar.com/avatar/{{hash[$index]}}" alt="Description" />
</div>
<div class="col-md-9">
<p>Review posted by: {{item.name}}</p>
<p>{{item.review}}</p>
<button ng-click="edit($index)">Edit</button>
<button ng-click="delete($index)">Delete</button>
</div>
</div>
Then in your controller:
$scope.edit = function(index) {
$scope.all[index] = // Your logic here.
};
$scope.delete = function(index) {
$scope.all[index] = // Your logic here.
};

Angular.js no scope in ng-include html template

I am learning as I go with my first Angular project and have ran into an issue.
Goal: When an link is clicked in a given .html template placed in with ng-include, I want it to change the value of $scope.selectedLocation
The issue: The value of $scope.selectedLocation does not change.
I read that the ng-include creates a child scope, so in order to change the parent scope variable, you could place $parent in front of the value. I have tried this and it does not work.
Main index page:
<body ng-app="photoApp" id="bodyDiv" >
<div ng-controller="PhotoGallery">
<div>
<ng-switch on="selectedLocation" >
<div ng-switch-when="home" >
<div ng-include="'home.html'"></div>
</div>
<div ng-switch-when="loc1">
<div ng-include="'file1.html'"></div>
</div>
<div ng-switch-when="loc2">
<div ng-include="'file2.html'"></div>
</div>
</ng-switch>
</div>
</div>
</body>
home.html code:
<div class="container-fluid">
<div class="row">
<div class="col-lg-6 col-md-6 col-sm-6">
<a href="#" ng-click="selectedLocation='loc1'">
Location 1
</a>
</div>
<div class="col-lg-6 col-md-6 col-sm-6">
<a href="#" ng-click="selectedLocation='loc2'">
Location 2
</a>
</div>
</div>
</div>
photoApp.js code:
var photoApp= angular.module('photoApp', []);
westonPhotographyApp.controller('PhotoGallery', function($scope)
{
$scope.selectedLocation ="home";
}
The issue is that you're binding to a primitive in an inherited scope. To fix it you should pass an object:
westonPhotographyApp.controller('PhotoGallery', function($scope)
{
$scope.vm = {
selectedLocation: "home"
}
}
Html
<div class="container-fluid">
<div class="row">
<div class="col-lg-6 col-md-6 col-sm-6">
<a href="#" ng-click="vm.selectedLocation='loc1'">
Location 1
</a>
</div>
<div class="col-lg-6 col-md-6 col-sm-6">
<a href="#" ng-click="vm.selectedLocation='loc2'">
Location 2
</a>
</div>
</div>
ng-include creates a new scope that inherits the parent (controller) scope through the prototype chain. In javascript you can't replace the value of the shadowed inherited property. Passing an object works as you're changing a property on a pointer to the object.
https://github.com/angular/angular.js/wiki/Understanding-Scopes
You seem to have misnamed your app variable. Either name westonPhotographyApp photoApp or vice-versa:
var photoApp = angular.module('photoApp', []);
photoApp.controller('PhotoGallery', function($scope) {
$scope.selectedLocation ="home";
}
Anyways, you could improve on your design:
You could use controllerAs syntax. It names your controller and makes it accessible throughout descendant scopes:
Index:
<div ng-controller="PhotoGallery as pgCtrl">
<div>
<ng-switch on="selectedLocation" >
<div ng-switch-when="home" >
<div ng-include="'home.html'"></div>
...
Home:
<div class="container-fluid">
<div class="row">
<div class="col-lg-6 col-md-6 col-sm-6">
<a href="#" ng-click="pgCtrl.selectedLocation='loc1'">
Location 1
</a>
</div>
<div class="col-lg-6 col-md-6 col-sm-6">
<a href="#" ng-click="pgCtrl.selectedLocation='loc2'">
Location 2
</a>
</div>
</div>
</div>
With your controller:
photoApp.controller('PhotoGallery', function() {
var vm = this;
vm.selectedLocation ="home";
}

Invoke function inside a controller from Fancybox2

I have this directive
app.directive('fancybox', function($compile, $timeout){
return {
link: function($scope, element, attrs){
$(element).fancybox({
'transitionIn': 'elastic',
'transitionOut': 'elastic',
'width': '250',
'height': '250',
'speedIn': 600,
'speedOut': 200,
'overlayShow': false,
afterLoad: function () {
$timeout(function(){
$compile($("#content-popup"))($scope);
$scope.$apply();
$.fancybox.resize();
})
this.title = $(this.element).next('.content-popup-footer').html();
},
helpers: {
title: {
type: 'inside'
}
},
});
}
}
});
I'm trying to invoke a function that is inside the controller that invoked the fancybox. This is the html that i'm sending to the fancybox
<a href="{{content.source}}" fancybox="fancybox" id="content-popup"
class="transparent-box content-popup content-picture-container"
rel="campaign-picture-popup" "><a/>
<!--Fancybox footer data begin-->
<div class="content-popup-footer" style="display:none">
<div class="row">
<div class="col-md-6 col-sm-6">
<div class="content-popup-user-info">
<img class="content_picture_profile_pic"
ng-src="{{content.photographer.instagramProfilePicture}}"/>
<div class="content_popup_user_name">
{{content.photographer.instagramUserName}}
</div>
<i class="fa fa-circle small-dot"></i>
<span id="instagram-picture-time-taken">{{content.timeTaken}}</span>
</div>
</div>
<div class="col-md-6 col-sm-6 content_popup_link_container">
<div class="content_popup_link">
<i class="fa fa-link"></i>
View source
</div>
</div>
</div>
<div class="row" id="content-popup-picture-info-row">
<div class="col-md-12">
<p>{{content.description}}</p>
</div>
<div class="col-md-12" id="content-popup-statistics">
<span><i class="fa fa-thumbs-o-up"></i>{{content.likesCount}}</span>
<span><i class="fa fa-comment-o"></i>{{content.commentsCount}}</span>
</div>
</div>
<form role="form">
<div class="form-body">
<div class="form-group">
<div class="input-icon">
<i class="fa fa-pencil-square-o"></i>
<input id="name" type="text" class="form-control"
placeholder="Add caption">
</div>
</div>
</div>
</form>
<div>
<button class="btn select-content-btn"
ng-click="onSelectedContent(content)"
ng-style="content.selected && {'background-color':'#2ecc71'} || !content.selected && {'background-color':'#95a5a6'}">
<i class="fa fa-check" ng-if="content.selected"></i>
<span ng-if="!content.selected">Select</span>
<span ng-if="content.selected">Selected</span>
</button>
</div>
</div>
</div>
<!--Fancybox footer data end-->
The problem that the scope doesn't being recognized inside the fancybox window and i can't invoke the onSelectedContent().
How can i add the scope to the fancybox window so i could activate all the scope's functions and props?

AngularJS - How to generate random value for each ng-repeat iteration

I am trying to create random span sized divs(.childBox) of twitter bootstrap using AngularJS.
<div ng-controller="HomeCtrl">
<div class="motherBox" ng-repeat="n in news">
<div class="childBox" class="col-md-{{boxSpan}} box">
<a href="#" class="thumbnail">
<img src="{{holderLink}}" height="200px" alt="100x100">
<p class="tBlock"> {{n.title}} </p>
</a>
</div>
</div>
</div>
controller('HomeCtrl', ['$scope', '$http', function($scope,$http) {
$http.get('news/abc.json').success(function(data) {
$scope.news = data;
});
$scope.holderSize = 150;
$scope.holderLink = 'http://placehold.it/'+$scope.holderSize+'x'+$scope.holderSize;
$scope.boxSpan = getRandomSpan();
function getRandomSpan(){
return Math.floor((Math.random()*6)+1);
};
}])
I want to create different integer value for boxSpan for each .childBox div but all .childBox have same boxSpan value. Although everytime i refresh page boxSpan creates random value.
How can i generate different/random value for each ng-repeat iteration?
Just call add getRandomSpan() function to your scope and call it in your template:
$scope.getRandomSpan = function(){
return Math.floor((Math.random()*6)+1);
}
<div ng-controller="HomeCtrl">
<div class="motherBox" ng-repeat="n in news">
<div class="childBox" class="col-md-{{getRandomSpan()}} box">
<a href="#" class="thumbnail">
<img src="{{holderLink}}" height="200px" alt="100x100">
<p class="tBlock"> {{n.title}} </p>
</a>
</div>
</div>
</div>
As an alternative to the accepted answer, since you're likely to reuse this function, you can turn it into a filter for convenience:
angular.module('myApp').filter('randomize', function() {
return function(input, scope) {
if (input!=null && input!=undefined && input > 1) {
return Math.floor((Math.random()*input)+1);
}
}
});
Then, you can define the max and use it anywhere on your app:
<div ng-controller="HomeCtrl">
<div class="motherBox" ng-repeat="n in news">
<div class="childBox" class="col-md-{{6 | randomize}} box">
<a href="#" class="thumbnail">
<img src="{{holderLink}}" height="200px" alt="100x100">
<p class="tBlock"> {{n.title}} </p>
</a>
</div>
</div>
</div>
Improvisation of the accepted answer to prevent digest overflow:
var rand = 1;
$scope.initRand = function(){
rand = Math.floor((Math.random()*6)+1)
}
$scope.getRandomSpan = function(){
return rand;
}
<div ng-controller="HomeCtrl">
<div class="motherBox" ng-repeat="n in news">
<div class="childBox" ng-init="initRand()" class="col-md-{{getRandomSpan()}} box">
<a href="#" class="thumbnail">
<img src="{{holderLink}}" height="200px" alt="100x100">
<p class="tBlock"> {{n.title}} </p>
</a>
</div>
</div>
</div>

Resources