Hiding individual divs in ng-repeat loop - javascript

I have a ng-repeat loop, which displays individual panels (one for each loop iteration). In each panel I have a 'mark as read' button that has a ng-click event. I want to be able to hide the panel that the mark as read button is clicked on, but so far I can only get all the panels to show and hide, not the individual selected panel.
How can I get the ng-click to hide the selected panel?
Thanks
Sorry here is some code of what I am doing now:
The panel section:
<section class="card" ng-repeat="item in notifications" ng-hide="msgRead">
<div class="item item-header notification wrap">
<h2>{{item.title}}</h2>
<div class="notification-content">
{{item.text}}
</div>
<button class="button button-block button-stable" ng-click="markAsRead(item.id)">
Mark As Read
</button>
</div>
</section>
And this is my controller function:
$scope.msgRead = true;
$scope.markAsRead = function (id) {
$scope.msgRead = $scope.msgRead === false ? true : false;
};
Stephen

You can write like:
<section class="card" ng-repeat="item in notifications" ng-hide="item.readonly">
<div class="item item-header notification wrap">
<h2>{{item.title}}</h2>
<div class="notification-content">
{{item.text}}
</div>
<button class="button button-block button-stable" ng-click="item.readonly = true">
Mark As Read
</button>
</div>
</section>
You don't need to write a scope method for this.

Related

How To Display A Unique Element Based On A Click Event In Angular 6

So I have two files. An app.component.ts file and an app.component.html file.
Below is an image example of what I want to achieve in my User Interface.
If you look at the photo, you'll see an action icon by the right displaying a nav box element.
I tried achieving something similar in my angular application and this is what I get any time I click on the action Icon:
All the nav boxes display on the UI when I click on the icon. This is because the nav element is inside a *ngFor loop.
Here is my code in the app.component.html file:
<div class="row" *ngFor="let picture of pictures">
<div class="cell">
<p>{{picture.name}}</p>
<p class="med-text meta space-text">{{picture.ticketid}}</p>
</div>
<div class="cell"><p class="meta">{{picture.email}}</p></div>
<div class="cell-photo"><p class="meta">{{picture.ticket_type}}</p></div>
<div class="cell-large">
<div class="toggle on">
<div class="toggle"></div>
</div>
</div>
<div class="small">
<div>
<div class="toggle-on" (click)="toggleActionNav()">
<div class="action"></div
</div>
<!--- nav-Element Starts ---->
<nav class="dropdown-list w-dropdown-list w--open" *ngIf ="actionNav">
<div>View Pictures</div>
<div >Edit Pictures</div>
</nav>
<!--- nav-Element Ends ---->
</div>
</div>
</div>
And here is the code on my app.component.ts file:
actionNav: boolean;
toggleActionNav() {
this.actionNav = !this.actionNav;
}
My question goes thus. How do I get the nav elements to display uniquely and not all displaying together at the same time, just like it is in the first photo?
All responses will be deeply appreciated. Thanks
You can, for example, add a showActionNav property to your picture object. Then you can do (click)="picture.showActionNav = !picture.showActionNav" to toggle it and *ngIf ="picture.showActionNav" to display it.
simplest answer would be just set flag,
for example, actionNavOpen in your object:
(click)="picture.actionNavOpen = !picture.actionNavOpen"
in navs ngIf do: *ngIf ="picture.actionNavOpen"
of course if you're heavily typed this will give you some errors.
so few tips what to do next:
toggling of this flag (actionNavOpen) should be via method
in this method you can also set all others flag in pictures to false
just remember you don't need to pre-set this flag to falsy - it's already falsy while you get this data from rest api
to remove type errors you should extend returning model (interface) from rest api with your model which has this particular flag (actionNavOpen)
if you could show the before and after image will help to understand the problem. Here the problem statement given , when clicking the icons overlap or design itself is overlapping ?
actionNav variable shouldn't be in component's scope. It should be part of picture object which you are using in the ngFor.
And, pass the picture object along with index to the toggleActionNav method to change the actionNav value.
Below is what you need.
<div class="row" *ngFor="let (picture, index) of pictures">
<div class="cell">
<p>{{picture.name}}</p>
<p class="med-text meta space-text">{{picture.ticketid}}</p>
</div>
<div class="cell">
<p class="meta">{{picture.email}}</p>
</div>
<div class="cell-photo">
<p class="meta">{{picture.ticket_type}}</p>
</div>
<div class="cell-large">
<div class="toggle on">
<div class="toggle"></div>
</div>
</div>
<div class="small">
<div>
<div class="toggle-on" (click)="toggleActionNav(picture, index)">
<div class="action"></div>
</div>
<!--- nav-Element Starts ---->
<nav class="dropdown-list w-dropdown-list w--open" *ngIf="picture.actionNav">
<div>View Pictures</div>
<div>Edit Pictures</div>
</nav>
<!--- nav-Element Ends ---->
</div>
</div>
</div>
And the toggle method needs to be like:
toggleActionNav(picture, index) {
//disable all the actionNavs to false
this.pictures.map(pictureObj => pictureObj.actionNav = false)
this.pictures[index] = true
}

Avoid JavaScript Replication in partial views

This code is used to remove a cart-item from a partial view.
$(document).on('click', '.RemoveLink', (function (e) {
e.preventDefault();
var recordToDelete = $(this).attr("data-id");
var itemID = $(this).attr("data-itemid");
if (recordToDelete != '') {
$.post("/ShoppingCart/RemoveFromCart", { "id": recordToDelete, "itemID": itemID },
function () {
$('.container-cart').load('#Url.Action("cartDropDown","ShoppingCart")', function () {
$('.cart-dropdown').css('display', 'inline-block');
}
);
});
}
}));
This works well for the first iteration but from the second iteration on-wards, every click of a remove of an item is resulting in deletion of 2 items of a kind. Suppose we had 4 items of pencils and 8 items of pens. Clicking delete pencil button once will result in deletion of 2 pencils and vice versa.
This is probably because of the logic used. Following is the html that is rendered when $('.container-cart').load('#Url.Action("cartDropDown","ShoppingCart")' executes:
#model OnlineStore.ViewModels.ShoppingCartViewModel
<div class="container-cart">
#if (Model.ItemCount == 0)
{
<div>
<span>
There are no items in your cart. Continue shopping.
</span>
</div>
}
else
{
<ul class="cart-dropdown">
<li>
<div class="cart-items cart-caption">
<ul>
#foreach (var i in Model.CartItems)
{
<li id="list-item-#i.item.ItemID">
<div class="container-fluid item-wrap" style="position: relative">
<div class="item-remove">
<a href="#" class="RemoveLink"
data-id="#i.RecordID" data-itemid="#i.item.ItemID">
x
</a>
</div>
<div class="col-md-2 item-img">
<div class="row-cart">
<img alt="" id="cartImg" height="71" width="75" src="#i.item.ImageUrl">
</div>
</div>
<div class="col-md-5 item-info">
<div class="row-cart">
<div class="brand-name">
<a href="#" class="brandName">
#i.item.BrandName
</a>
</div>
<div class="product-name">
<a href="#" class="productName">
#i.item.ItemName
</a>
</div>
<div class="product-qty">
<p class="productQTY" id="item-count-#i.item.ItemID">
#i.Count x #i.item.ItemPrice
</p>
</div>
</div>
</div>
<div class="col-md-5 price-info">
<div class="row-cart" style="margin-top: 10px">
<div class="col-md-6">
<div class="row-mrp">
<span class="cartItemPrice" id="item-total-#i.item.ItemID">
Rs #(#i.Count * #i.item.ItemPrice)
</span>
</div>
</div>
</div>
</div>
</div>
</li>
}
</ul>
</div>
</li>
<li class="clearfix">
<div class="col-md-6">
<div class="row-cart sub-cost" style="background: #fff; margin-left: -10px; margin-right: 0">
<p>
Sub Total :
<span style="float: right">
Rs
<span class="ng-binding"></span>
</span>
</p>
<p>
Delivery Charge :
<span qa="delChargeMB" style="float: right">Free</span>
</p>
</div>
<div class="row-cart cart-chkout-btn">
<button type="button">View Basket & Checkout</button>
</div>
</div>
</li>
</ul>
}
</div>
This html is the partial view that is initially rendered when user clicks a button to view the cart-items. So when user clicks on 'remove an item' button on this partial view, an ajax call is sent to server to remove an item from the cart-items and on success, load the UI again by rendering this partial view once again with new values from the database.
All this is working fine for the first iteration of the deletion of an item from the cart-item list. But when I'm deleting an item again as a second deletion, code is running twice. I'm guessing this is because <div class="container-cart"> is rendered twice on the page as after the first deletion, I can see it on the live DOM inside the browser that <div class="container-cart"> is encolsed inside another <div class="container-cart"> and then the normal elements are rendered in sequence. I'm guessing maybe that's why javaScript is rendered twice or running twice.
Please suggest what you think about it and help me resolve it.
Thanks in advance
After deletion of an item try to use location.reload(); instead of hitting the MVC action method again!

Dynamic button click hide and show functionality in Meteor

I have hide and show functionality on dynamically generated cards after form submission.
{{#each newaction}}
<div class="workflowcard">
<div class="module-card-small">
<div class="res-border"></div>
<div class="card-img">{{team}}</div>
<div class="res-content">
<div class=" newaction-name">{{action_title}}</div><hr>
<div class="newaction-des">{{description}}</div>
<!-- <div class=" due-on">Due on:{{d_date}}</div><hr>-->
</div>
<div class="due">
Due on:
<div>
<div class="day-stamp">{{weekday d_date}}</div>
<div class="date-stamp">{{date d_date}}</div>
<div class="month-stamp">{{month d_date}}</div>
</div>
</div>
{{> actioncardsubcontent}}
</div>
<div class="btn-box">
<button type="button" class="cancelsub">Hide Option</button>
<button type="submit" class="createbtnsub">Show Options</button>
</div>
</div>
</div>
{{/each}}
</div>
</div>
<template name="actioncardsubcontent">
<div class="subcontent" >
<div class="modulepath"><div>{{module_list}}</div></div>
<div class="linkto"><div>Linked To: <div class="linkto-color">{{link}}</div></div></div>
<div class="description"><div>Notes:<br>{{description}}</div></div>
</div>
</template>
When I click on show options button the action card subcontent is displaying and when I click on hide option it is hiding.
The problem is, the hide and show functionality is applying for all the cards which are creating dynamically at a time when I click on single card. I understand the reason is I have given the class name for the buttons. So how to stop that and make it work to current target.
Here is my JS:
Template.actioncardsubcontent.rendered = function(){
this.$(".subcontent").hide();
};
Template.workflow.events({
"click .createbtnsub":function(){
$('.subcontent').show();
},
"click .cancelsub":function(){
$('.subcontent').hide();
}
What you need to do is give a unique ID for each iteration to your cards div class attribute.
in JSTL usually has indexId attribute. You can use that and set your class.
Sample:
{{#each newaction indexId="i"}}
{{/each}}
<div class="btn-box">
<button type="button" class="cancelsub<%=i%>">Hide Option</button>
<button type="submit" class="createbtnsub<%=i%>">Show Options</button>
</div>
In your javascript:
use i to hide.
You have a couple of options here. The one I prefer is to put everything in the {{#each}} into its own template. If you do that, you can put the button click events inside of the child template's event which makes it much simpler to manipulate your data. An example:
Templates:
<template name='workflow'>
{{#each newaction}}
{{> card}}
{{/each}}
</template>
<template name='card'>
<div class="workflowcard">
<div class="module-card-small">
<div class="res-border"></div>
<div class="card-img">{{team}}</div>
<div class="res-content">
<div class=" newaction-name">{{action_title}}</div><hr>
<div class="newaction-des">{{description}}</div>
</div>
<div class="due">
Due on:
<div>
<div class="day-stamp">{{weekday d_date}}</div>
<div class="date-stamp">{{date d_date}}</div>
<div class="month-stamp">{{month d_date}}</div>
</div>
</div>
{{> actioncardsubcontent}}
</div>
<div class="btn-box">
<button type="button" class="cancelsub">Hide Option</button>
<button type="submit" class="createbtnsub">Show Options</button>
</div>
</div>
</div>
</template>
Javascript (template.$ docs):
Template.cards.events({
"click .createbtnsub":function(event, template){
template.$('.subcontent').show();
},
"click .cancelsub":function(event, template){
template.$('.subcontent').hide();
}
});
-- OR --
You can do a better DOM query.
Without more info on what is actually in the actioncardsubcontent template or proper testing, this is a best guess on what you're trying to find. You should be able to tweak this query to meet your specific needs easily enough through trial and error. Please read the jQuery Traversing docs as it should clear this up a bit for you.
Template. workflow.events({
"click .createbtnsub":function(event, template){
$(event.target).siblings('.due').find('.subcontent').show();
},
"click .cancelsub":function(event, template){
$(event.target).siblings('.due').find('.subcontent').hide();
}
});

Trigger event when uib-accordion is opened

I´m trying to trigger an event when the accordion is opened. The event should just get triggered when the accordion is getting opened, not when getting closed.
HTML:
<uib-accordion>
<uib-accordion-group is-open="status.open" ng-click="showList(status.open)"
ng-init="count=0">
<uib-accordion-heading>
I can have markup, too! <i class="pull-right glyphicon"
ng-class="{'glyphicon-chevron-down': status.open,
'glyphicon-chevron-right': !status.open}"></i>
</uib-accordion-heading>
{{count}}
</uib-accordion-group>
</uib-accordion>
App.js (inside the Controller)
$scope.showList = function (status){
if(status)
{
$scope.count = $scope.count + 1;
}
};
For the sake of simplicity the event just increments count by one. I just want to know how to trigger an event when the accordion is opened.
this is an old thread, but since I bumped into the same issue, here is the solution I came up with.
uib-accordion[-group] directive has toggleOpen() scoped function. so you cannot change that from outside controller.
let's override template - accordion takes template-url. take the original template from:
https://github.com/angular-ui/bootstrap/blob/master/template/accordion/accordion-group.html
and create your own
remove toggleOpen() from root <div> and <a> tags.
while you feeding uib-accordion-heading, bind click/key-press event with your controller function - ie) myToggleOpen(myIsOpenModel) make sure your heading covers whole section
in myToggleOpen, do what you need
html
<uib-accordion>
<div uib-accordion-group template-url="myTemplate.html" ng-repeat="item in items track by $index" is-open="item.isOpen">
<uib-accordion-heading>
<div ng-click="myToggleOpen(item)">Toggle!</div>
</uib-accordion-heading>
<div class="content">
Hello!
</div>
</div>
</uib-accordion>
js
scope.myToggleOpen = function (item) {
item.isOpen = !item.isOpen;
}
myTemplate.html (change more if needed)
<div role="tab" id="{{::headingId}}" aria-selected="{{isOpen}}" class="panel-heading">
<h4 class="panel-title">
<a role="button" data-toggle="collapse" href aria-expanded="{{isOpen}}" aria-controls="{{::panelId}}" tabindex="0" class="accordion-toggle" uib-accordion-transclude="heading" ng-disabled="isDisabled" uib-tabindex-toggle><span uib-accordion-header ng-class="{'text-muted': isDisabled}">{{heading}}</span></a>
</h4>
</div>
<div id="{{::panelId}}" aria-labelledby="{{::headingId}}" aria-hidden="{{!isOpen}}" role="tabpanel" class="panel-collapse collapse" uib-collapse="!isOpen">
<div class="panel-body" ng-transclude></div>
</div>

Toggle Content based on button click in a view

I have a small angular app going and I'm stuck on something that seems so simple! (New to angular here).
Scenario:
I have two buttons on the page that should toggle the display of their associated content.
Few things need to happen:
Buttons:
1. Should be an active button on page load (also displaying its appropriate content)
2. When other button is clicked, this should change the active state (for button and associated content)
3. If active button is clicked, nothing should happen. It should stay active.
Can't figure out how to do this. All help is appreciated.
Code
<div class="toggle-btns">
<button class="toggle-btns__btn toggle-btns__btn--active">Button 1</button>
<button class="toggle-btns__btn" >Button 2</button>
</div>
<div class="content-one">
<!-- content here -->
</div>
<div class="content-two">
<!-- content here -->
</div>
If you can't figure this out, you clearly haven't tried very hard ;)
I'd do something like this:
<div class="toggle-btns">
<button class="toggle-btns__btn" ng-click="content = 1" ng-class="{ toggle-btns__btn--active: content == 1}">Button 1</button>
<button class="toggle-btns__btn" ng-click="content = 2" ng-class="{ toggle-btns__btn--active: content == 2}">Button 2</button>
</div>
<div class="content-one" ng-show="content == 1">
<!-- content here -->
</div>
<div class="content-two" ng-show="content == 2">
<!-- content here -->
</div>
In your controller:
angular.module('Blah')
.controller('MainCtrl', ['$scope', function($scope) {
$scope.content = 1;
});
There are literally 1 000 000 ways of doing that.
One way of using data binding in view:
<div class="toggle-btns" ng-init="active = true">
<button ng-click="active = true" class="toggle-btns__btn toggle-btns__btn--active">Button 1</button>
<button ng-click="active = false" class="toggle-btns__btn" >Button 2</button>
</div>
<div ng-if="active" class="content-one">
<!-- content here -->
<p>content1</p>
</div>
<div ng-if="!active" class="content-two">
<!-- content here -->
<p>content2</p>
</div>
Plnkr here: http://plnkr.co/edit/bVK9VUum7KRLNccgPc5D?p=preview

Categories