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.
Related
What I need to do is to display the filtered array in the DOM once I click on any value from the dropdown. The return from filtered function is right but I couldn't update the DOM.
HTML CODE
This is my side dropdown list that I take the value from
<div class="col-md-3">
<div class="widget">
<h4 class="widget-title">Sort By</h4>
<div>
<select class="form-control" (change)="selectChangeHandler($event)">
<option value="Man">Man</option>
<option value="Women">Women</option>
<option value="Accessories">Accessories</option>
<option value="Shoes">Shoes</option>
</select>
</div>
</div>
</div>
Table that shows the results on DOM take the value from above dropdown list to be able to show them by category. Unfortunately the DOM doesn't change (I used NGX pagination library), please see my TS code that sends the filtered array to the loop? So, I don't understand why it didn't update.
<div class="col-md-9">
<div class="row" id="top">
<div class="col-md-4" *ngFor="let item of collection | paginate: { itemsPerPage: 100, currentPage: p ,id: 'foo' }">
<div class="product-item">
<div class="product-thumb">
<span class="bage">Sale</span>
<img class="img-responsive" src="https://via.placeholder.com/150" alt="product-img" />
<div class="preview-meta">
<ul>
<li>
<span data-toggle="modal" data-target="#product-modal">
<i class="fas fa-search"></i>
</span>
</li>
<li>
</i>
</li>
<li>
<i class="fas fa-shopping-cart"></i>
</li>
</ul>
</div>
</div>
<div class="product-content">
<h4>{{item.name}}</h4>
<p class="price">{{item.price}}</p>
</div>
</div>
</div>
Type Script Code
export class AllproductsComponent implements OnInit {
allProducts:any[]=[]
filteredData=[...this.allProducts]
p: number = 1;
collection: any[] = this.filteredData;
constructor(private _allproducts:ProductService) {
console.log(this.collection);
}
ngOnInit(): void {
this.getAllProducts()
}
getAllProducts():any{
this._allproducts.getAllproducts().subscribe(res=>{
console.log(res.data);
this.allProducts = res.data
this.collection =res.data
})
}
pageChanged(pee:number){
document.getElementById("top").scrollIntoView()
}
selectChangeHandler(value:any){
console.log(value.target.value);
console.log(this.filteredData);
this.filteredData = this.allProducts.filter(key=>{
if(value.target.value === "Man"){
if(key.price > 20)return this.allProducts
}else if(value.target.value === "Women"){
if(key.price < 20) return this.allProducts
}else {
return this.allProducts
}
})
console.log(this.filteredData);
}
}
I appreciate your help, thanks a lot.
allProducts:any[]=[]
filteredData=[...this.allProducts]
collection: any[] = this.filteredData;
you are initializing data before it is called from your api , so it's normal it will never work. You have to reinitialize it inside your method
this._allproducts.getAllproducts().subscribe(res=>{ ..});
I'm working on a system where the user can select a product and go to the next page. This product then gets saved in the session using laravel sessions. When the user decides to go to the next page and come back. The chosen product is indeed saved in the session, but the is no way for them to see what product they have chosen because the class isn't applied to the product that was chosen.
The code may clarify it better:
#foreach($themes as $theme)
<div class="col-md-4 mb-4">
<div class="card theme-card card-hover depth-2 border-0" id="theme-id-{{$theme->id}}">
<a href="" class="theme-link" data-toggle="modal" data-target="#theme{{ $theme->id }}">
<div class="card-image" style="height: 200px; background-image: url('/uploads/{{ $theme->thumbnail }}'); background-size: cover; background-position: center center;"></div>
<div class="card-body">
<div class="row">
<div class="col-md-2 vertical-center">
<i class="fab fa-magento fa-lg"></i>
</div>
<div class="col-md-10">
<p class="m-0">{!! str_limit($theme->name, $limit = 32, $end = '...') !!}</p>
<small class="text-muted">{{ $theme->productable_type }}</small>
</div>
</div>
</div>
</a>
<div class="card-footer bg-white border-0 text-right pt-0">
<div class="row">
<div class="col-md-6 text-left">
<input type="hidden" class="theme-name" name="theme[{{$theme->id}}]">
{{--<input type="hidden" value="{{ $theme->composer_package }}">--}}
<button data-card-id="{{$theme->id}}" class="btn btn-orange btn-sm btn-theme-choice">Kiezen</button>
</div>
<div class="col-md-6 text-right">
<span style="font-size: 20px;" >€ {{ $theme->price }} EUR</span>
</div>
</div>
</div>
</div>
</div>
#endforeach
In the above code, I for each trough every so-called "Theme" and I'm giving the ID of the theme as a data target and as ID. Then in my Javascript code, I do the following:
$('.btn-theme-choice').on('click', function (event) {
event.preventDefault();
newSelectedCardId = $(event.target).data('card-id');
if(cardId === null) {
cardId = newSelectedCardId;
} else if (cardId !== newSelectedCardId) {
$('#theme-id-' + cardId).removeClass('theme-chosen').find("input[name='theme["+cardId+"]']").val('');
cardId = null;
}
var card = $('#theme-id-' + cardId );
card.toggleClass('theme-chosen');
selectedCardInput = card.find("input[name='theme["+cardId+"]']");
if( !$('.theme-card').hasClass('theme-chosen') ) {
selectedCardInput.val('');
} else if ( $('.theme-card').hasClass('theme-chosen') ) {
selectedCardInput.val('selected');
}
console.log(selectedCardInput);
});
Here I add the class to the card so the user can See which card they've selected. This choice then gets saved in the session using some PHP code in the controller
if( $theme == null ) {
return redirect('plugins');
} elseif( $theme != null ) {
foreach($this->predefinedArray as $value) {
$request->session()->put('chosen_theme.' . $value, $theme->$value);
}
$request->session()->put('chosen_theme.composer_package', $theme->productable->composer_package);
return redirect('plugins');
}
problem
How can I read the session and add the class to the card with the IDs that were stored in the session so if the person leaves the page and comes back, they can see what cards they've selected?
Thanks in advance
Try this in your view..
<div class="card theme-card card-hover depth-2 border-0 {{ \Session::get('chosen_theme.composer_package') == $theme->id ? 'theme-chosen' : '' }}" id="theme-id-{{$theme->id}}">
Whenever the theme id is in the session and the page loaded the class will be added, and if it is not in the session then the class won't be added.
Let me know the result..
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.
I dont understand why i am getting this Internal server error 500. Also because of the items aren't being hidden as i want them to. The console output is saying that the '$' isnt defined which isnt right i dont believe since i am link jquery.
HTML:
<template name="room">
<div class="container-fluid">
<h1> Sprint Retrospective</h1>
<form id="tagSearchForm" class="navbar-form navbar-right" role="search">
<div class="form-group">
<span><i class="fa fa-filter"></i></span>
<input id="filters" type="text" class="form-control" placeholder="Filter tags...">
</div>
<button id="filterTagsButton" type="button" class="btn btn-default">Filter</button>
</form>
{{> card}}
<hr>
<div class="container-fluid">
<div class="row">
<div class="col-xs-6 col-sm-6">
<h2> Good category </h2>
<ul class="fa-ul">
{{#each goodCards}}
<div class="row">
<div id="card" class="card-panel green">
<span class="white-text">
{{text}}
</span>
<div class="card-action">
<div class="chip">
<i id="deleteCardButton" class="material-icons fa fa-trash-o"></i>
Remove Card
</div>
{{#each tags}}
<div class="chip">
<tag class="tag" id="{{this}}">{{this}}</tag>
<i id="removeTag" class="material-icons fa fa-ban"></i>
</div>
{{/each}}
</div>
</div>
</div>
{{/each}}
</ul>
</div>
<div class="col-xs-6 col-sm-6">
<h2> Bad category </h2>
<ul class="fa-ul">
{{#each badCards}}
<div class="row">
<div id="card" class="card-panel red accent-4">
<span class="grey-text">
{{text}}
</span>
<div class="card-action">
<div class="chip">
<i id="deleteCardButton" class="material-icons fa fa-trash-o"></i>
Remove Card
</div>
{{#each tags}}
<div class="chip">
<tag class="tag" id="{{this}}">{{this}}</tag>
<i id="removeTag" class="material-icons fa fa-ban"></i>
</div>
{{/each}}
</div>
</div>
</div>
{{/each}}
</ul>
</div>
</div>
</div>
</div>
</template>
js:
Meteor.methods({
filterSingleTag: function(tag){
var numCards;
numCards = $(".card-panel").length;
for(var i = 0; i < numCards;i++){
var compTags;
var found;
found = false;
compTags = $(".card-panel").eq(i).find(".tag");
for(var j = 0; j < compTags.length; j++){
var str;
str = "" + compTags[j].firstChild;
if(str.toLowerCase() == tag){
found = true;
}
}
if(!found)
$(".card-panel").eq(i).hide();
}
},
filterMulitpleTags: function(tags){
var numCards;
numCards = $(".card-panel").length;
for(var i = 0; i < numCards;i++){
var compTags;
var found;
found = false;
compTags = $(".card-panel").eq(i).find(".tag");
for(var j = 0; j < compTags.length; j++){
var str;
str = "" + compTags[j].text;
if(tags.indexOf(str.toLowerCase()) >= 0)
found = true;
}
if(!found)
$(".card-panel").eq(i).hide();
}
},
clearFilter: function(){
var numCards;
numCards = $(".card-panel").length;
for(var i = 0; i < numCards;i++){
$(".card-panel").eq(i).show();
}
}
});
console:
Exception while invoking method 'filterSingleTag' ReferenceError: $ is not defined
I20160208-13:36:40.290(-6)? at [object Object].Meteor.methods.filterSingleTag (/home/thouse/Retrospectre/src/.meteor/local/build/programs/server/app/js/room.js:145:20)
I20160208-13:36:40.290(-6)? at maybeAuditArgumentChecks (/home/thouse/Retrospectre/src/.meteor/local/build/programs/server/packages/ddp-server.js:1785:12)
I20160208-13:36:40.291(-6)? at /home/thouse/Retrospectre/src/.meteor/local/build/programs/server/packages/ddp-server.js:872:20
I20160208-13:36:40.291(-6)? at [object Object]._.extend.withValue (/home/thouse/Retrospectre/src/.meteor/local/build/programs/server/packages/meteor.js:1021:17)
I20160208-13:36:40.291(-6)? at /home/thouse/Retrospectre/src/.meteor/local/build/programs/server/packages/ddp-server.js:871:41
I20160208-13:36:40.291(-6)? at [object Object]._.extend.withValue (/home/thouse/Retrospectre/src/.meteor/local/build/programs/server/packages/meteor.js:1021:17)
I20160208-13:36:40.291(-6)? at /home/thouse/Retrospectre/src/.meteor/local/build/programs/server/packages/ddp-server.js:870:46
I20160208-13:36:40.292(-6)? at tryCallTwo (/home/thouse/.meteor/packages/promise/.0.5.1.1550ocw++os+web.browser+web.cordova/npm/node_modules/meteor-promise/node_modules/promise/lib/core.js:45:5)
I20160208-13:36:40.292(-6)? at doResolve (/home/thouse/.meteor/packages/promise/.0.5.1.1550ocw++os+web.browser+web.cordova/npm/node_modules/meteor-promise/node_modules/promise/lib/core.js:171:13)
I20160208-13:36:40.292(-6)? at new Promise (/home/thouse/.meteor/packages/promise/.0.5.1.1550ocw++os+web.browser+web.cordova/npm/node_modules/meteor-promise/node_modules/promise/lib/core.js:65:3)
I20160208-13:36:40.293(-6)? at [object Object]._.extend.protocol_handlers.method (/home/thouse/Retrospectre/src/.meteor/local/build/programs/server/packages/ddp-server.js:848:21)
I20160208-13:36:40.293(-6)? at /home/thouse/Retrospectre/src/.meteor/local/build/programs/server/packages/ddp-server.js:729:85
Meteor methods are defined and executed on the server (also the client, depending on where they're defined). Since the server doesn't have access to jQuery, $ is undefined and it's throwing an error. It looks like you want to just execute some client-side code when something happens. In that case, you're looking for events:
In your client-side js code:
Template.yourTemplateName.events({
'click #filterTagsButton' (event, template) {
// Your stuff from your question goes here.
}
});
I can't tell which one is single versus multiple based on your example, but I think you can get the gist from here. I'd highly recommend reading the Meteor Guide for this kind of thing.
In my KnockoutJS app, I am looping over an observable array and displaying some stuff like this:
<div id="user-list-container" data-bind="foreach: users">
<div class="row order-line list-row">
<div class="medium-7 small-10 columns">
<i class="fi-torso tip-right"></i>
</div>
<div class="medium-3 columns">
<a href="#" class="button split tiny info radius">
<i data-bind="text:role"></i>
<span data-dropdown="leftDrop" data-options="align:left"></span>
</a>
</div>
<div class="medium-2 small-2 columns">
<i class="fi-trash" title="#Texts.Remove"></i>
</div>
<ul id="leftDrop" class="f-dropdown" data-dropdown-content>
<li>Foreman</li>
<li>Worker</li>
</ul>
</div>
</div>
Everything works fine and all the elements are shown, but when I click one item to operate on that particular item, each item then has the value of last item in the array.
In my Javascript function:
self.makeWorker = function (user) {
var project = self.selectedProject();
var account = self.accounts.findByKey(user.accountId);
var ur = user;
console.log(user);
console.log(this);
if (project.role() != "Worker") {
var data = {
role: "Worker",
organizationId: project.organizationId,
projectId: project.id,
accountId: user.accountId
}
TippNett.Project.ChangeRole(data, function (result) {
project.users.findByKey(user.id).role("Worker");
ur.role("Worker");
account.roles.findByKey(user.id).role("Worker");
});
}
}
The value passed to the function is always the last value in 'users' observable array.
Any input on why this is happening? See the image for more briefing: