Why value in directive does not get updated - Angular Js? - javascript

I just encounter a problem I have written a directive but its not getting update, I dont know why, in console it does change but in directive it does not.
Here is my directive
mainControllers.directive('mallsproduct', function () {
return {
restrict: 'E',
scope: {
productInfo: '=info',
linkid: '=linkid'
},
templateUrl: 'directives/dashboard_product.html'
};
});
Here is my `html`
<div class="aa-properties-content-body mg-7" ng-controller="DashboardController as ctrl">
<ul class="aa-properties-nav aa-list-view">
<li style="border: 1px solid #ccc;margin-bottom: 25px;" ng-repeat="active_products in productInfo.items">
<article class="aa-properties-item mg-top-0-notimp">
<a class="aa-properties-item-img" href="#/product/{{active_products.id}}">
<img ng-if="active_products.photos[0].path" resize-image alt="img" class="" src="{{active_products.photos[0].path}}">
<img ng-if="!active_products.photos[0].path" resize-image class="" src="img/default_product.jpg" alt="">
</a>
<div class="aa-properties-item-content">
<div class="aa-properties-about padding-0-notimp">
<h5>{{active_products.name| limitTo : 10}}{{active_products.name.length > 10 ? '...' : ''}}</h5>
<p class="font-size-11-imp"><i class="fa fa-building-o" aria-hidden="true"></i> {{active_products.mall.name| limitTo : 10}}{{active_products.mall.name.length > 10 ? '...' : ''}}</p>
<p class="font-size-11-imp"><i class="fa fa-map-marker" aria-hidden="true"></i> {{active_products.mall.address| limitTo : 10}}{{active_products.mall.address.length > 10 ? '...' : ''}}</p>
<p class="font-size-11-imp"><i class="fa fa-phone" aria-hidden="true"></i> {{active_products.shop.telephone}}</p>
<p class="font-size-11-imp" ng-if="linkid == 3"><i class="fa fa-eye" aria-hidden="true"></i> {{active_products.views}}</p>
<div class="modal-demo">
<script type="text/ng-template" id="myModalContent.html">
<div ng-include src="'partials/update_product.html'"></div>
</script>
<div ng-controller="AddProductController">
<button ng-click="view_product(active_products.id)"><i class="fa fa-pencil" aria-hidden="true"></i></button>
<button ng-click="del_product(active_products.id)"><i class="fa fa-trash-o" aria-hidden="true"></i></button>
<button ng-if="linkid == 2" ng-init="status = 1" ng-click="reactivate_product(active_products.id, status)"><i class="fa fa-lock" aria-hidden="true"></i></button>
</div>
<div class="modal-parent">
</div>
</div>
</div>
</div>
</article>
</li>
</ul>
<div class="aa-title pad-top-30" ng-if="linkid == 1">
<p>Global page count for active product is {{global_pagecount}} and active product count from API is {{productInfo._meta.pageCount}}</p>
<h3 ng-if="global_pagecount < productInfo._meta.pageCount" class="text-align-center color-feroz cursor-pointer" ng-click="load_more(global_pagecount, linkid)">{{$root.translated_labels.dashboard.load_more}}</h3>
</div>
<div class="aa-title pad-top-30" ng-if="linkid == 3">
<p>Global page count for most viewed is {{global_pagecount_mostv}} and most viewed count from API is {{productInfo._meta.pageCount}}</p>
<h3 ng-if="global_pagecount_mostv < productInfo._meta.pageCount" class="text-align-center color-feroz cursor-pointer" ng-click="load_more(global_pagecount_mostv, linkid)">{{$root.translated_labels.dashboard.load_more}}</h3>
</div>
</div>
I am including directive in dashboard partial like this
<div class="active tab-pane" ng-if="linkid === '1'">
<malls-product info="active_products" linkid="linkid"></malls-product>
</div>
<!--Active products list ends here -->
<!-- Get Inactive Products -->
<div class="active tab-pane" ng-if="linkid === '2'" >
<malls-product info="$root.inactive_products" linkid="linkid"></malls-product>
</div>
<!--Get Inactive products ends here -->
<div class="active tab-pane" ng-if="linkid === '3'" >
<malls-product info="$root.mostviewed_products" linkid="linkid"></malls-product>
</div>
<!-- View Profile-->
and This is the api which does show the result in console.
$scope.global_pagecount = 1;
$scope.active_product = function () {
$http.get($rootScope.baseurl + 'abc?&page=' + $scope.global_pagecount,
{headers:
{'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': $rootScope.keyword_auth_token, 'Accept-Language': $cookies.get('type')}
})
.success(function (data) {
//$scope.active_product_pageCount = data._meta.pageCount;
if ($scope.global_pagecount === 1) //I know for sure the first page of pagination is 1
{
$scope.active_products = data;
}
if ($scope.global_pagecount > 1) // If user click load more global count gets incremented and new results push in active_producst
{
/* for loading new results Pagination Applied */
for (var times = data.items.length - 1; times >= 0; times--) {
$scope.active_products.items.push(data.items[times]);
}
}
console.log($scope.active_products);
})
.error(function (data) {
// console.log(data);
});
};
What is the issue, why it is not getting update, If I use rootscopethen it works fine, obviously it has too, but not with $scope.
Note : when scope.global_pagecount value is equal to 2 i get new results but not in directive only in console. By default scope.global_pagecount has value equal to 1.

You don't use your directive correctly. You define it as:
mainControllers.directive('mallsproduct'
Which means you should use it as:
<mallsproduct ..>
Or define your directive camelcased:
mainControllers.directive('mallsProduct'
Then you can use it as you do now:
<malls-product ..>

This is because of the Isolated scope doesn’t know anything about its parent scope. You just created a directive with an isolated scope.
To access any parent scope data, we need to pass the scope data to our directive explicitly. This is achieved by setting properties on the scope object in the DDO.
Another important thing is that, these properties also MUST be set as the attributes of the directive html element.

Related

Pass a value to another controller which executes first

I have two controllers headerController, aboutController.
headerController -> To maintain the navigation and redirection
aboutController -> works when about-us page loads.
My issue is I have to update the headerController variable value when aboutController loads. i.e When about us page loads, the navigation about-us should active, similar to all the pages.
This is my code:
app.service('shareService', function () {
var data;
return {
getProperty: function () {
return data;
},
setProperty: function (value) {
data = value;
}
};
});
app.controller('headerController', function ($scope, shareService) {
$scope.navigation = [
{url: '#!/home', name: 'Home'},
{url: '#!/about-us', name: 'About Us'},
{url: '#!/services', name: 'Services'}
];
var data = shareService.getProperty();
console.log(data);
$scope.selectedIndex = 0;
$scope.itemClicked = function ($index) {
console.log($index);
$scope.selectedIndex = $index;
};
});
app.controller('aboutController', function ($scope, shareService) {
console.log('test');
$scope.selectedIndex = 1;
shareService.setProperty({navigation: $scope.selectedIndex});
});
header.html:
<header ng-controller="headerController">
<div class="header">
<div class="first-half col-md-6">
<div class="row">
<div class="logo">
<img src="assets/img/logo.png" alt=""/>
</div>
</div>
</div>
<div class="second-half col-md-6">
<div class="row">
<div class="social-share">
<ul id="social-share-header">
<li><i class="fa fa-facebook" aria-hidden="true"></i></li>
<li><i class="fa fa-twitter" aria-hidden="true"></i></li>
<li><i class="fa fa-google-plus" aria-hidden="true"></i></li>
</ul>
</div>
</div>
</div>
<nav>
<ul ng-repeat="nav in navigation">
<li class="main-nav" ng-class="{ 'active': $index == selectedIndex }"
ng-click="itemClicked($index)">
{{nav.name}}
</li>
</ul>
</nav>
</div>
</header>
index.html
This is how my template works.
<body ng-app="myApp">
<section class="first-section">
<div ng-include="'views/header.html'"></div>
</section>
<section class="second-section">
<div ng-view></div>
</section>
<section class="last-section">
<div ng-include="'views/footer.html'"></div>
</section>
</body>
Update 1: Added index.html file.
Update 2: Issue explanation: If I run directly to the about us page, then still the home navigation is on active. But it should be About us
What is you are looking for is event based communication between your controllers. This can be easily done using. $rootScope.$on, $rootScope.$emit and $rootScope.$broadcast. Since explaining all three of them in this answer will be overkill. Kindly go through this article

Angular ng-show if in array

I have a ng-repeat for article comments, that looks like this:
<div ng-repeat="comment in comments">
<li class="item" ng-class-even="'even'">
<div class="row">
<div class="col">
<i class="icon ion-person"></i> {{ comment.user.first_name }} {{ comment.user.last_name }}
<i class="icon ion-record"></i> {{ comment.created_at }}
</div>
<!-- TODO: this needs to be an ng-if admin -->
<div ng-show="hasRole(comment.user)" class="col right">
<i class="icon ion-record admin"></i> Admin
</div>
</div>
<div class="row">
<div class="col">
<p>{{ comment.text }}</p>
</div>
</div>
</li>
</div>
I am trying to show this part only if the user is an admin:
<div ng-show="hasRole(comment.user)" class="col right">
<i class="icon ion-record admin"></i> Admin
</div>
I have tried to set that up following the answers here.
So I made a function in my controller:
$scope.hasRole = function(roleName) {
return $scope.comments.user.roles.indexOf(roleName) >= 0;
}
But it returns -1 every time, even when the user is an admin. My data looks like this:
1:Object
$$hashKey: "object:28"
article_id:"2"
created_at:"2016-05-12 12:19:05"
id:6
text:"someCommentText"
updated_at:null
user:Object
active:"1"
created_at:null
first_name:"admin"
id:1
last_name:"admin"
roles:Array[1]
0:Object
created_at:null
id:1
name:"Admin"
parent_id:null
pivot:Object
slug:"admin"
Use this in your HTML
<div ng-show="hasAdminRole(comment.user.roles)" class="col right">
<i class="icon ion-record admin"></i> Admin
</div>
this is the method to determine that the user belongs to the admin role or not.
$scope.hasAdminRole = function(roles) {
var isAdmin = false;
for(var i = 0; i < roles.length; i++) {
if (roles[i].name == 'Admin') {
isAdmin = true;
break;
}
}
return isAdmin;
}
Perhaps you have an error on this line?
var indexOfRole = $scope.comments.indexOf(user.roles);
You are looking here to see if the list of roles for this users exists within the array of comments.
Maybe you need to just check in the actual user.roles array and see if there is an Admin role there? Something like:
$scope.hasRole = function(user) {
for (var i = 0; i < user.roles.length; i++) {
if (user.roles[i].slug === 'admin') { return true; }
}
return false
}
That's because it's an object, you can fetch the index of only array. In the link that you provided is an array.

Update parent scope through child scopes in Angular

<div class="full-row" ng-repeat="row in pendingRequests | orderBy: '-modificationDate' | partition:3">
<div class="one-third" ng-repeat="request in row track by request.id">
<div class="incoming_request" ng-class="actionClass(request)">
<div class="request_comments">
<hr>
<p><span>Recipients:</span></p>
<div class="comments">
<p ng-repeat="comment in request.comments track by comment.id" class="dont-break-out">
<span class="author" ng-bind="comment.userName | employeeName">:</span>
{{comment.text}}
<span ng-if="comment.status == State.APPROVED" class="approval success" ng-click="changestatus(comment, request)"><i class="fa fa-check"></i></span>
<span ng-if="comment.status == State.REJECTED" class="approval error" ng-click="changestatus(comment, request)"><i class="fa fa-times"></i></span>
<span ng-if="comment.status == State.PENDING" class="approval" ng-click="changestatus(comment, request)" title="{{showApproveTooltip(comment)?'Click to approve the request on behalf of this user':''}}"><i class="fa fa-clock-o"></i></span>
</p>
</div>
</div>
<div class="request_resolve">
<hr>
<div class="textarea-holder">
<textarea placeholder="Your comment..." ng-model="request.newComment" ng-model-options="{ updateOn: 'default blur'}"></textarea>
</div>
<div class="button-container">
<button ng-click="approve(request);" ng-disabled="request.isProcessing" class="btn btn-primary" am-hide-request-resolve-div>Confirm<i ng-hide="request.isProcessing" class="fa fa-check"></i><span ng-show="request.isProcessing" class="spinner no-hover"><a><i class="fa-li fa fa-spinner fa-spin"></i></a></span></button>
<button ng-click="reject(request);" ng-disabled="request.isProcessing" class="btn btn-default pull-right" am-hide-request-resolve-div>Reject <i class="fa fa-times"></i></button>
</div>
</div>
Here is peace of code. As You may see there are many ng-repeats. My pendingRequests collection very often is updated from server. After 3 or more updates when I click on some button nothing is happend on UI.
Details :
On approve click I change status of one comment.
$scope.approve = function (request) {
var currentUserComment = request.comments.filter(function(comm) {
return comm.userId == user.id && comm.status == "Pending";
})[0];
currentUserComment.status = State.APPROVED; // change comments Status
currentUserComment.text = request.newComment;
delete request.newComment;
if (!currentUserComment) {
request.isProcessing = false;
return;
}
Comments.update(currentUserComment, function() {
// $rootScope.$broadcast('daysUpdated');
});
request.isProcessing = false;
};
This must show this span <span ng-if="comment.status == State.APPROVED" class="approval success" ng-click="changestatus(comment, request)"><i class="fa fa-check"></i></span> , cause now status is equal to State.APPROVED. But nothing happens.
After some research I think it all because ng-repeat and collection updates.
ng-repeat creates a child scope for each item, and so the scopes in play might look like this:
bookCtrl scope = { tags: [ 'foo', 'bar', 'baz' ] }
ng-repeat child scopes: { tag: 'foo' }, { tag: 'bar' }, { tag: 'baz' }
So when I update comment.status for some request Angular don't know in what scope it exists.
Am I right? And how can I solve my problem (after changing comment status show correct span)?
More Simple code :
<div ng-repeat="request in requests">
<div ng-repeat="comment in request.comments">
<span ng-if="comment.status == State.APPROVED" class="approval success"><i class="fa fa-check"></i></span>
<span ng-if="comment.status == State.REJECTED" class="approval error"><i class="fa fa-times"></i></span>
<span ng-if="comment.status == State.PENDING" class="approval"><i class="fa fa-clock-o"></i></span>
</div>
<div>
<button ng-click="approve(request)">
Approve
</button>
</div>
</div>
And approve function :
var user = LoggeInUser(); // some user who is loggedIn now
$scope.approve = function(request){
var currentUserComment = request.comments.filter(function(comm) {
return comm.userId == user.id && comm.status == "Pending";
})[0];
currentUserComment.status = State.APPROVED; // change comments Status
Comments.update(currentUserComment, function() { // send PUT request to API
// $rootScope.$broadcast('daysUpdated');
});
}
You may find your solution in moving the functions to $scope.functions.functionName. I believe from reviewing this that you are running into scoping issues, as you alluded to in your statement.
JS
$scope.functions.approve = function () { ... }
HTML
functions.approve(request)
You also might have a look at using controller as, sometimes that can help:
https://docs.angularjs.org/api/ng/directive/ngController

ng-click show data in angular js

I want to show data using ng-click
First i have listing for of all the companies, this works fine. it displays all the companies.:
<div class="col-xs-3" ng-repeat="item in companyData">
<a ng-click="getPackageInfo({id:item.iCompanyID})" class="block panel padder-v bg-primary item">
<span class="text-white block">{{item.vCompanyName}}</span>
</a>
</div>
Now on click of company name, i have to display other info like packges of that company, for that i have done this under above div:
<div ng-repeat="item in pData" class="col-xs-3">
<a ng-click="" class="block panel padder-v bg-primary item">
<span class="text-white block">{{item.vPackageName}}</span>
</a>
</div>
In controller.js i did this, getPackageInDetail will return package listing according to company id:
function getPackageInfo(id) {
SubscriptionoptioncompanylistFactory.getPackageInDetail(id).
success(function(data) {
$scope.pData = data;
}).
error(function(data,status,header,config) {
$scope.pData = 0;
});
};
How can i append the data according to company clicked?
Array.prototype.push.apply() can be used for merging two arrays.
Merge the second array into the first one
//Define an empty array
$scope.pData = [];
$scope.getPackageInfo = function(id) {
SubscriptionoptioncompanylistFactory.getPackageInDetail(id).
success(function(data) {
Array.prototype.push.apply($scope.pData, data); //Merge the array
});
};
Additionally, I think you need to pass ID properly
<a ng-click="getPackageInfo(item.iCompanyID)">

Angular JS / Ui router - Post Image URL in StateParams

I've a little issue : In my HomePage, I've an NG-repeat with image in post. When I want click in one post, I have this error :
TypeError: Cannot read property 'facebook' of undefined
at new <anonymous> (app.js:234)
at invoke (ionic.bundle.js:12877)
at Object.instantiate (ionic.bundle.js:12885)
at ionic.bundle.js:17154
at IonicModule.controller.self.appendViewElement (ionic.bundle.js:48176)
at Object.IonicModule.factory.ionicViewSwitcher.create.switcher.render (ionic.bundle.js:46392)
at Object.IonicModule.factory.ionicViewSwitcher.create.switcher.init (ionic.bundle.js:46312)
at IonicModule.controller.self.render (ionic.bundle.js:48050)
at IonicModule.controller.self.register (ionic.bundle.js:48008)
at updateView (ionic.bundle.js:53315)
AND
GET http://127.0.0.1:8103/%7B%7BauthData.facebook.cachedUserProfile.picture.data.url%7D%7D 404 (Not Found)
This is my HTML :
<div ng-repeat="(id,post) in posts">
<div class="card" ui-sref="tabpost({ postname: post.nameid, postdescription: post.descriptionid, postdate: post.startdateid, posthour: post.starthourid, postprice: post.priceid, postnbguest: post.nbguestid, postpicture: post.pictureid })">
<div class="item item-divider" ng-class="{{post.starthourid | setImageClass}}">
<h2 class="text stable"> {{ post.nameid }} </h2>
<h3 class="text stable" id="header-date">
<i class="icon ion-clock"></i> Le {{ post.startdateid | date : "d MMM" }} à {{ post.starthourid | date : "HH:mm" }}</p>
</div>
<div class="row">
<div class="col">
<h3><i class="icon ion-ios-location"></i> À 500m</h3></div>
<div class="col"><h3><i class="icon ion-ios-people">
</i> 2/{{ post.nbguestid }} </h3></div>
</div>
<button class="button button-stable" id="positive-btn-price" disabled>{{ post.priceid }}€</button>
<img class="imgProfilPostPositive" src="{{ post.userid.facebook.cachedUserProfile.picture.data.url }}">
<div class="item item-divider" id="footerPostNotepositive"><p> <i class="fa fa-star"></i> Popular </p> </div>
</div>
</div>
</div></div>
App JS :
.state('tabpost', {
url: '/tabpost/:postname/:postdescription/:postdate/:posthour/:postprice/:postnbguest/:postpicture',
templateUrl: 'templates/tab-post.html',
controller: 'PostCtrl',
})
Controller JS :
$scope.nameid = $stateParams.postname;
$scope.descriptionid = $stateParams.postdescription;
$scope.startdateid = $stateParams.postdate;
$scope.starthourid = $stateParams.posthour;
$scope.priceid = $stateParams.postprice;
$scope.nbguestid = $stateParams.postnbguest;
$scope.userid.facebook.cachedUserProfile.picture.data.url = $stateParams.postpicture;
How can I pass my picture in my Post page ?
Thanks for your time.
Using Angular markup like {{hash}} in a src attribute doesn't work right: The browser will fetch from the URL with the literal text {{hash}} until Angular replaces the expression inside {{hash}}. The ngSrc directive solves this problem.
The buggy way to write it:
<img src="http://www.gravatar.com/avatar/{{hash}}" alt="Description"/>
The correct way to write it:
<img ng-src="http://www.gravatar.com/avatar/{{hash}}" alt="Description" />
https://docs.angularjs.org/api/ng/directive/ngSrc

Categories