I am confused about how to show an .active class on a clicked item when using the ng-repeat directive. Here's a Plunker.
Here's my view:
<h4>Arctic Videos</h4>
<ul class="list-unstyled">
<li class="clearfix" ng-repeat="item in videos" ng-class="{ active: $index }" style="padding-bottom: 2em;">
<div style="float: left; position:relative;">
<img class="img-thumbnail" ng-src="{{item.thumbUrl}}" width="100" height="68" alt="">
</div>
<h4>{{item.title}}</h4>
</li>
</ul>
My script.js
var ArcticApp = angular.module('ArcticApp', ['ngRoute', 'ngSanitize']);
ArcticApp.config(function($routeProvider){
$routeProvider
.when('/', {
templateUrl: './partials/map.html',
controller: 'MainController'
})
.when('/videos/:itemId', {
templateUrl: './partials/videos.html',
controller: 'VideoController'
})
.otherwise({
redirectTo: '/'
})
});
ArcticApp.controller('MainController', function($scope){
$scope.message = "This is the map page!";
});
ArcticApp.controller('VideoController', function($scope, $routeParams, $sce){
$scope.videos = [
{
"blockquote": "et sint quae\nqui odio fugit quia aut modi id maxime\nsequi qui et",
"title": "Canada",
"synopsis": "<p>Some text will go here and there. Some more will go here.</p><p>Yet even some more text will go here and there. yes, tehre's even more here.</p>",
"id": 897,
"thumbUrl": "http://placehold.it/100x68"
},
{
"blockquote": "sit molestiae possimus ut in explicabo\nea autem saepe a iusto est exercitationem at\ndistinctio quia consectetur nulla vel maxime",
"title": "USA",
"synopsis": "<p>Some text will go here and there. Some more will go here.</p><p>Yet even some more text will go here and there. yes, tehre's even more here.</p>",
"id": 471,
"thumbUrl": "http://placehold.it/100x68"
},
{
"blockquote": "recusandae natus minus est saepe alias\nvero amet quia natus voluptatem ut saepe dolor rem\nperspiciatis quia unde quia cum aliquam sint",
"title": "Russia",
"synopsis": "<p>some text can go here </p>",
"id": 400,
"thumbUrl": "http://placehold.it/100x68"
}
];
$scope.whichItem = $routeParams.itemId;
$scope.trustAsHtml = $sce.trustAsHtml.bind($sce);
});
How would I go about assigning an active class to a clicked item?
Use
ng-class="{ active: selectedVideo === item }"
And
ng-click="selectVideo(item)"
In the controller, add
$scope.selectVideo = function(video) {
$scope.selectedVideo = video;
}
you can use it like this
<li class="clearfix" ng-repeat="(key,item) in videos" ng-class="{ active:(condition) }" style="padding-bottom: 2em;">
key is the number of iteration and condition can be any Boolean logic to make active class true
like
ng-class="{ active: 1==1 }
in this case since 1==1 is true so active class will be printed .
Related
I have comments that i loop through:
When i click on the three dots i want there to pop a little div out with the text "repport comment".
But when i click on one of buttons they all open :
import { FaEllipsisV } from "react-icons/fa";
import "./styles.css";
import React from "react";
const data = [
{
postId: 1,
id: 1,
name: "id labore ex et quam laborum",
email: "Eliseo#gardner.biz",
body:
"laudantium enim quasi est quidem magnam voluptate ipsam eos\ntempora quo necessitatibus\ndolor quam autem quasi\nreiciendis et nam sapiente accusantium"
},
{
postId: 1,
id: 2,
name: "quo vero reiciendis velit similique earum",
email: "Jayne_Kuhic#sydney.com",
body:
"est natus enim nihil est dolore omnis voluptatem numquam\net omnis occaecati quod ullam at\nvoluptatem error expedita pariatur\nnihil sint nostrum voluptatem reiciendis et"
},
{
postId: 1,
id: 3,
name: "odio adipisci rerum aut animi",
email: "Nikita#garfield.biz",
body:
"quia molestiae reprehenderit quasi aspernatur\naut expedita occaecati aliquam eveniet laudantium\nomnis quibusdam delectus saepe quia accusamus maiores nam est\ncum et ducimus et vero voluptates excepturi deleniti ratione"
},
{
postId: 1,
id: 4,
name: "alias odio sit",
email: "Lew#alysha.tv",
body:
"non et atque\noccaecati deserunt quas accusantium unde odit nobis qui voluptatem\nquia voluptas consequuntur itaque dolor\net qui rerum deleniti ut occaecati"
},
{
postId: 1,
id: 5,
name: "vero eaque aliquid doloribus et culpa",
email: "Hayden#althea.biz",
body:
"harum non quasi et ratione\ntempore iure ex voluptates in ratione\nharum architecto fugit inventore cupiditate\nvoluptates magni quo et"
}
];
export default function App() {
const [showOptions, setShowOptions] = React.useState(false);
return (
<div className="App">
{data.map((comment, index) => (
<div key={index} className="comment-container">
{comment.name}
<button onClick={() => setShowOptions(!showOptions)}>
<FaEllipsisV />
</button>
{showOptions ? (
<div className="options">Report this comment</div>
) : null}
</div>
))}
</div>
);
}
https://codesandbox.io/s/elated-roentgen-fbjr7?file=/src/App.js:0-2121
Example of what i'd like :
You can do something like this:
export default function App() {
const [showOptions, setShowOptions] = React.useState({ id: null, status: false });
return (
<div className="App">
{data.map((comment, index) => (
<div key={index} className="comment-container">
{comment.name}
<button onClick={() => setShowOptions({ id: comment.id, status: !showOptions.status })}>
<FaEllipsisV />
</button>
{showOptions.status && comment.id === showOptions.id ? (
<div className="options">Report this comment</div>
) : null}
</div>
))}
</div>
);
}
I am attempting to create an angularjs bootstrap accordion that scrolls the accordion to the top when opened.
These solutions are close to what I would like to do:
AngularJS / ui-bootstrap accordion - scroll to top of active (open) accordion on click
https://www.peterbouda.eu/making-an-angular-ui-bootstrap-accordion-scrolling-to-top-when-opening.html
However, they use a timeout or scope watches. I would like to avoid using these unless absolutely necessary.
Is there a way to accomplish this without using $watch or setTimeout?
Here is a plunk of what i am trying to do, this is using the $watch: https://plnkr.co/edit/XQpUdrdjqaCGom4L9yIJ
app.directive( 'scrollTop', scrollTop );
function scrollTop() {
return {
restrict: 'A',
link: link
};
}
function link( scope, element ) {
scope.collapsing = false;
var jqElement = $( element) ;
scope.$watch( function() {
return jqElement.find( '.panel-collapse' ).hasClass( 'collapsing' );
}, function( status ) {
if ( scope.collapsing && !status ) {
if ( jqElement.hasClass( 'panel-open' ) ) {
$( 'html,body' ).animate({
scrollTop: jqElement.offset().top - 30
}, 500 );
}
}
scope.collapsing = status;
} );
}
The directive can be simplified to:1
app.directive( 'scrollTop', function scrollTop($timeout) {
return {
restrict: 'A',
link: postLink
};
function postLink(scope, elem, attrs) {
elem.on("click", function(e) {
if (scope.status.isOpen) {
$timeout(function() {
$( 'html,body' ).animate({
scrollTop: elem.offset().top - 30
}, 500 );
});
}
});
}
})
<uib-accordion>
<div heading="Section Title" is-open="status.isOpen"
ng-repeat="section in vm.sections"
scroll-top
uib-accordion-group>
<uib-accordion-heading>
<div ng-class="{isOpen: vm.isOpen}">
<h3>{{section.sectionTitle}}</h3>
<p>{{section.sectionSubHeader}}</p>
</div>
</uib-accordion-heading>
<div class="clearfix">
<b>Index+1={{$index+1}}</b>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</div>
</div>
</uib-accordion>
The $timeout is necessary because the browser needs to render the DOM with the newly opened and closed elements before it can compute the proper scroll offset.
The DEMO on PLNKR
I have found a way to do this from the controller.
I added a function that is triggered on ng-click to report the is-open status of the accordion.
Using the component lifecycle hook $doCheck I was able to watch for changes to the state of vm.isOpen. $doCheck runs on the end of every digest cycle, so I did not need to set a $scope.watch or $timeOut
The $doCheck runs essentially the same code as the directive in the question
app.controller('homeController', function($state, $element, sections, $transitions) {
var vm = this;
vm.$onInit = function() {
vm.sections = sections.getSections();
};
function updateOpenStatus() {
vm.collapsing = false;
vm.isOpen = vm.sections.some(function(item) {
return item.isOpen;
});
}
vm.$doCheck = function() {
if (vm.isOpen) {
var elem = $element.find('.panel-collapse');
var status = elem.hasClass('collapsing');
if (vm.collapsing && !status) {
var parentElem = elem.closest('.panel-open');
if (elem.parent().hasClass('panel-open')) {
$('html,body')
.stop()
.animate({
scrollTop: parentElem.offset().top - 52
}, 'fast');
}
}
vm.collapsing = status;
}
};
});
I updated the uib-accordion to call the function in the controller
<uib-accordion>
<div heading="Section Title" is-open="section.isOpen" ng-repeat="section in vm.sections" scroll-top uib-accordion-group>
<uib-accordion-heading>
<div ng-class="{isOpen: section.isOpen}" ng-click="vm.toggleOpen()">
<h3>{{section.sectionTitle}}</h3>
</div>
</uib-accordion-heading>
<div class="clearfix">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</div>
</div>
</uib-accordion>
Updated Plnkr: https://plnkr.co/edit/5EqDfmVOa0hzFfaQqdI0?p=preview
I face an issue while retrieving single row/data from angular to html. I need to print the title. Below is the code of angular controller (partial):
vm.showJoke = function(joke){
console.log(joke);
$http.get('http://localhost:8000/api/v1/jokes/' + joke, {
//body: joke.joke,
//user_id: $rootScope.currentUser.id
//user_id: localstorageUser.role_id
}).success(function(response) {
//console.log(response.data.joke);
vm.jokes_show = response.data.joke;
console.log(vm.jokes_show);
$scope.MessageAll = 'Joke shows! ';
}).error(function(){
console.log("error");
$scope.MessageAll = 'Please try again';
});
}
Below is my HTML codes:
<span ng-hide="showEnabled">
<span class="glyphicon glyphicon-th-large" data-ng-click="jokes.showJoke(joke.joke_id)"></span>
</span>
<span ng-show="showEnabled" style="background-color:powderblue;">
<p style="background-color:powderblue;" ng-model="jokes_show"></p>
</span>
Here is the response I found below:
{joke_id: 3, joke: "Quia in enim voluptates neque. Ullam eligendi ipsu…iente qui perferendis libero. Ut aut qui sint et.", submitted_by: "admin"}
joke
:
"Quia in enim voluptates neque. Ullam eligendi ipsum eaque magni sit fugit in. Voluptate sapiente qui perferendis libero. Ut aut qui sint et."
joke_id
:
3
submitted_by
:
"admin"
See the image for the same too.
Your help most welcome.
I was wondering if some of you could lighten me and try to explain what I miss in this : http://plnkr.co/edit/opxB2Jfi0Xf0Tq1780vz?p=preview
Looks quite simple to me but does not work.
My code:
<section ng-app="myApp">
<div ng-controller="myCtrl">
<ul ng-init="tab=1">
<li ng-repeat="item in data">
<a href ng-click="tab = item.thingy">{{item.name}}</a>
</li>
</ul>
<div ng-repeat="item in data" ng-show="tab === item.thingy">
<img ng-src="{{item.img}}" width="50px"><br>
{{item.year}}</div>
</div>
</section>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', ['$scope',
function($scope) {
$scope.data = [{
name: "First",
title: "oneTitle",
description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
year: "2013",
img: "http://static.hdw.eweb4.com/media/wp_400/1/5/42735.jpg",
thingy: 1
}, {
name: "third",
title: "twoTitle",
description: "Quisque pulvinar libero sed eros ornare",
year: "2014",
img: "http://static.hdw.eweb4.com/media/wp_400/1/1/8519.jpg",
thingy: 2
}, {
name: "Second",
title: "threeTitle",
description: "Cras accumsan massa vitae tortor vehicula .",
year: "2015",
img: "http://static.hdw.eweb4.com/media/wp_400/1/5/43326.jpg",
thingy: 3
}, {
name: "fourth",
title: "FourTitle",
description: "Suspendisse vitae mattis magna.",
year: "2011",
img: "http://static.hdw.eweb4.com/media/wp_400/1/5/42413.jpg",
thingy: 4
}];
}
]);
</script>
Thank you in advance!
modifications in script.js:
var app = angular.module('myApp', []);
app.controller('myCtrl', ['$scope', function ($scope) {
$scope.data = [{
name: "First",
title: "oneTitle",
description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
year: "2013",
img: "http://static.hdw.eweb4.com/media/wp_400/1/5/42735.jpg",
thingy: 1
}, {
name: "third",
title: "twoTitle",
description: "Quisque pulvinar libero sed eros ornare",
year: "2014",
img: "http://static.hdw.eweb4.com/media/wp_400/1/1/8519.jpg",
thingy: 2
}, {
name: "Second",
title: "threeTitle",
description: "Cras accumsan massa vitae tortor vehicula .",
year: "2015",
img: "http://static.hdw.eweb4.com/media/wp_400/1/5/43326.jpg",
thingy: 3
}, {
name: "fourth",
title: "FourTitle",
description: "Suspendisse vitae mattis magna.",
year: "2011",
img: "http://static.hdw.eweb4.com/media/wp_400/1/5/42413.jpg",
thingy: 4
}];
$scope.details = $scope.data[0];
$scope.GetDetails = function(obj)
{
$scope.details = obj;
}
}]
);
In HTML:
<section ng-app="myApp">
<div ng-controller="myCtrl">
<ul ng-init="tab=1">
<li ng-repeat="item in data">
<a href ng-click="GetDetails(item);">{{item.name}}</a>
</li>
</ul>
<div>
{{details.thingy}} <br/>
{{details.name}}<br/>
{{details.title}}<br/>
{{details.description}}<br/>
{{details.year}}<br/>
<img ng-src="{{details.img}}" width="50px"><br>
</div>
</div>
</section>
Basically second ng-repeat is not required
I've been stuck on something for some time now and need some help. I'm trying to build a tab control that allows me to dynamically add tabs with HTML content. The tab control that I found uses an id element to reference the url for the tab. What' I've found is that I can hardcode the id with my tab name and it will work, but if I use an expression {{eisEvent.url}} the $compile will not evaluate this to the real name. I would have put this in a fiddle, but JSFiddle is having some major problems today, so I'll paste the code instead. It's just three files.
style.css
ul {
list-style: none;
padding: 0;
margin: 0;
}
li {
float: left;
border: 1px solid #000;
border-bottom-width: 0;
margin: 3px 3px 0px 3px;
padding: 5px 5px 0px 5px;
background-color: #CCC;
color: #696969;
}
#mainView {
border: 1px solid black;
clear: both;
padding: 0 1em;
}
.active {
background-color: #FFF;
color: #000;
}
tabs.js
var myApp = angular.module('TabsApp', []);
myApp.service('EISEventService', function($rootScope) {
var eisSubscriptions = [];
this.addSubscription = function( eisEvent ){
console.log( eisEvent.name + "\n" + eisEvent.message );
$rootScope.$broadcast( "EVENT_ADDED", eisEvent );
eisSubscriptions.push( eisEvent );
};
this.removeSubscription = function( eisEvent ){
//TODO Remove the element from the array.
$rootScope.$broadcast( "EVENT_REMOVED", eisEvent );
};
});
myApp.controller('TabsCtrl', function ($scope, EISEventService) {
console.log("Initializing Tab Controller");
$scope.eisEvent = {};
$scope.tabs = [{
title: 'One',
url: 'one.tpl.html'
}, {
title: 'Two',
url: 'two.tpl.html'
}];
$scope.currentTab = 'one.tpl.html';
$scope.onClickTab = function (tab) {
$scope.currentTab = tab.url;
};
$scope.isActiveTab = function(tabUrl) {
return tabUrl == $scope.currentTab;
};
$scope.$on('EVENT_ADDED', function( event, args ){
console.log( "EventName : " + event.name );
var eisEvent = args;
console.log("EIS Event = " + eisEvent.name );
console.log("Message = " + eisEvent.message );
console.log("URL = " + eisEvent.url );
$scope.eisEvent = eisEvent;
$scope.tabs.push( {title : eisEvent.name, url:eisEvent.url });
// By doing this, it seems to work, but I need the second option to work because I will eventually retrieve this HTML from
// the server that will need to be parsed.
// Option 1
$scope.tabs_html.push( {html: '<script type="text/ng-template" id="'+eisEvent.url+'">Hello Event: '+eisEvent.name+'</script>' });
// Option 2
//This doesn't appear to work because of the binding.
//$scope.tabs_html.push( {html: '<script type="text/ng-template" id="{{eisEvent.url}}">Hello Event: {{eisEvent.url}}</script>' });
// Option 3
//If I hard code the ID it will work. For example if I enter test in the text box on the demo, the code below will work.
//$scope.tabs_html.push( {html: '<script type="text/ng-template" id="test_url">Hello Event: {{eisEvent.url}}</script>' });
});
$scope.tabs_html = [];
});
myApp.controller('AddCtrl', function($scope, EISEventService) {
$scope.onAddClick = function(){
console.log("add clicked");
var eisEvent = { name : $scope.txtName, url: $scope.txtName+"_url", message: "This is a log message"};
EISEventService.addSubscription(eisEvent);
}
});
myApp.directive("bindCompiledHtml", function($compile, $timeout) {
return {
template: '<div></div>',
scope: {
rawHtml: '=bindCompiledHtml'
},
link: function(scope, elem, attrs) {
scope.$watch('rawHtml', function(value) {
if (!value) return;
// we want to use the scope OUTSIDE of this directive
// (which itself is an isolate scope).
var newElem = $compile(value)(scope.$parent);
elem.contents().remove();
elem.append(newElem);
});
}
};
});
And Lastly tabs.html
<!DOCTYPE html>
<html ng-app="TabsApp">
<head>
<title></title>
<link rel="stylesheet" type="text/css" href="style.css">
<!--<script src="../lib/angular.min.js"></script>-->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.21/angular.min.js"></script>
<script src="tabs.js"></script>
</head>
<body >
<div>
<div id="add" ng-controller="AddCtrl">
<input type="text" ng-model="txtName">
<button ng-click="onAddClick()">Add</button>
</div>
<div id="tabs" ng-controller="TabsCtrl">
<ul>
<li ng-repeat="tab in tabs"
ng-class="{active:isActiveTab(tab.url)}"
ng-click="onClickTab(tab)">{{tab.title}}</li>
</ul>
<div id="mainView">
<div ng-include="currentTab"></div>
</div>
<script type="text/ng-template" id="one.tpl.html">
<div>
<h1>View One</h1>
<p>Praesent id metus massa, ut blandit odio. Proin quis tortor orci. Etiam at risus et justo dignissim congue. Donec congue lacinia dui, a porttitor lectus condimentum laoreet. Nunc.</p>
</div>
</script>
<script type="text/ng-template" id="two.tpl.html">
<div>
<h1>View Two</h1>
<p>Curabitur vulputate, ligula lacinia scelerisque tempor, lacus lacus ornare ante, ac egestas est urna sit amet arcu. Class aptent taciti sociosqu.</p>
</div>
</script>
<script type="text/ng-template" id="three.tpl.html">
<div>
<h1>View Three</h1>
<p>In pellentesque faucibus vestibulum. Nulla at nulla justo, eget luctus tortor. Nulla facilisi. Duis aliquet egestas purus in blandit. Curabitur vulputate, ligula lacinia scelerisque tempor, lacus lacus ornare ante, ac egestas est urna sit amet arcu. Class aptent taciti sociosqu.</p>
</div>
</script>
<div>
<div ng-repeat="tab in tabs_html" bind-compiled-html="tab.html"></div>
</div>
</div>
</div>
</body>
</html>
You can just run the app, type in some text and click the add button. This will add a tab with the URL that's the same. See the JavaScript comments in the JS file for Option 1, Option 2, and Option 3. Currently Option 1 is uncommented to show that it works. If you comment this out and uncomment Option 2, this is the option that I need to work but cannot get it to work.
I've made a Plunk for you
What if you $compile the html first, like this
var htmlString = '<script type="text/ng-template" id="{{eisEvent.url}}">Hello Event: {{eisEvent.url}}</script>';
var htmlElement = $compile(htmlString)($scope);
$scope.tabs_html.push( {html: htmlElement });
You must of course inject the compile service
myApp.controller('TabsCtrl', function ($scope, EISEventService, $compile) {