[Angular JS]- Tabs Pane Example - Dynamic Add Tab - angularjs

I have used the example from Angular JS Homepage and modified it to meet the requirements.
I have added the tabs info in a scope array and manipulate the data based in some conditions.
Issues:
I have attached an ng-bind on tabItem.title, so any change in the text box will update the title, but i want to limit the displaying of the title by 10 chars
When i create a new tab, i want that tab to be the selected one.
How can i select a tab based on some action taken (like on a click move from tab 1 to tab 2)
Fiddle: http://jsfiddle.net/austinnoronha/NWwcT
<br/><br/>
<div ng-cloak ng-app="TabsApp">
<div class="container" ng-controller="TabManagerCtrl">
<span class="label label-info label-ext" ng-click="tabManager.addTab()" style="cursor:pointer">Add a Tab</span><br/><br/>
<div>
<div tabs>
<div ng-repeat="tabInfo in tabManager.tabItems" pane title="{{ tabInfo.title }}">
<p>{{ tabInfo.content }}</p>
<input type="text" ng-model="tabInfo.title" ng-change="tabManager.getTitle(tabInfo)">
</div>
</div>
</div>
<br/><br/><br/>
</div><!-- /container -->
</div> <!-- /container -->
</div> <!-- /app -->

that's strange...
The limitTo filter doesn't seem to work, but you can create a new one and change your line
<div ng-repeat="tabInfo in tabManager.tabItems" pane title="{{ tabInfo.title }}">
by
<div ng-repeat="tabInfo in tabManager.tabItems" pane title="{{ tabInfo.title | limit:10}}">
with
angularApp.filter('limit', function() {
return function (input, value) {
return input.substr(0,value);
};
});
For the select one, I think it doesn't work because you have to have access to the pane scope. One way to do it is to access to access the property from the pane when you create it. In the pane directive, just add :
if(scope.$parent.tabInfo.selected) tabsCtrl.select(scope);
just after the tabsCtrl.addPane(scope); line. But then you also have to change the tabs directive so that the line
$scope.select = function(pane) {
become
this.select = $scope.select = function(pane) {
For your 3rd question, I don't know how to do it in that scheme.
I would make the pane directive different, putting the select function out of the directive, and binding it directly to your tabManager object.
Like this : http://jsfiddle.net/NWwcT/2/
In this cas, you have the 3 requirements, and you can select the tab from ouside by calling tabManager.select(index)

Related

AngularJS- How to handle each button created by ng-repeat

I am new to AngularJS.
I have created <li> to which I used ng-repeat.
<li> contains images and buttons like like, comment and share which is inside <li> and created by ng-repeat.
I have made function which will replace empty like button to filled like button (By changing background image of button).
But problem is this trigger applies to only first like button and other buttons does not change.
How can I fix this?
Code:
HTML:
<html>
<body>
<ul>
<li ng-repeat="media in images"><div class="imgsub">
<label class="usrlabel">Username</label>
<div class="imagedb">
<input type="hidden" value="{{media.id}}">
<img ng-src="{{ media.imgurl }}" alt="Your photos"/>
</div>
<!-- <br><hr width="50%"> -->
<div class="desc">
<p>{{media.alt}}</p>
<input type="button" class="likebutton" id="likeb" ng-click="like(media.id)" ng-dblclick="dislike(media .id)"/>
<input type="button" class="commentbutton"/>
<input type="button" class="sharebutton"/>
</div>
</div> <br>
</li><br><br><br>
</ul>
</body>
</html>
JS:
$scope.like = function(imgid)
{
document.
getElementById("likeb").
style.backgroundImage = "url(src/assets/like-filled.png)";
alert(imgid);
}
$scope.dislike = function(imgid)
{
document.
getElementById("likeb").
style.backgroundImage = "url(src/assets/like-empty.png)";
}
Thanks for help & suggestions :)
The id for each button should be unique but in your case, it's the same for all buttons ('likeb').
You can set the value of the attribute 'id' for each button dynamically by using '$index' and passing '$index' to the functions as follows:
<input type="button" class="likebutton" id="{{$index}}" ng-click="like($index)" ng-dblclick="dislike($index)"/>
Then in your controller, you can use the functions with the passed value.
For example,
$scope.like = function(index)
{
document.
getElementById(index).
style.backgroundImage = "url(src/assets/like-filled.png)";
}
Another good alternative in your case would be to use the directive ngClass.
use 2 css class for styling liked and disliked state, and then put the class conditionally with ng-class instead of DOM handling. and if you really want to perform a DOM operation (I will not recommend) then you can pass $event and style $event.currentTarget in order to perform some operation on that DOM object.

How to use ng-repeat in multiple div's?

I am working with angularJS ng-repeat. So, I want to use my ng-repeat value in another div. I am doing the following. But it doesn't loop through and give me the exact value.
Code in ng-repeat
<div uib-slide index="$index" class="uibSlider" ng-repeat='id in code' ng-click="$parent.ContentId = id.ContentId" ng-class="{'selected' : ContentId.Id === ContentId}">
<paragraph tag>{{id.ContentId}}</paragraph tag>
</div>
Code in Another Div
<div>
<label>{{(code| filter: {Id: ContentId}: true)[1].ContentId}}</label>
</div>
So, the problem is I have bunch of data and in the another div if I make the array value from 0 to 1. i'm getting null value. But automatically the value isn't changing based on what I contentID select. It always gives me the same value. I'm not sure where I'm going wrong.
Any Help would be appreciated.
You can use ng-repeat-start | ng-repeat-end
<div uib-slide ng-repeat-start='id in code'>
<paragraph tag>{{id.ContentId}}</paragraph tag>
</div>
<div ng-repeat-end>
<label>{{(id.ContentId}}</label>
</div>
If you are trying to show the same data in a modal, depending where the user clicks:
<div ng-repeat="id in code">
<!-- when the user clicks here, the modal will open. The ID will be the same as the one clicking -->
<a ng-click="openModal(id)">Open modal for id: {{id}}</a>
</div>
Then in your controller you will have a function called openModal which takes a parameter (id) that will open the modal and pass along the data.

Override ng-hide on ng-click

On the process of trying to learn angularjs, I am creating a set of divs using ng-repeat. I have five divs in all. I am only displaying the first div using $firstdirective component.
<div class="container" ng-app="demoApp" ng-controller="demoController">
<div class="row" ng-repeat="job in jobs" ng-hide="!$first">
<div class="col-md-4">
{{job}}
</div>
<div class="col-md-4">
<button class="btn-primary btn-xs add" ng-click="showNext($event)" ng-hide="$last">Add</button>
<button class="btn-primary btn-xs delete" style="display: none;">Delete</button>
</div>
</div>
</div>
That works.
Now, each div has two buttons, Add and Delete. When I click add I want to hide the add button and delete button of the current row and open the next row. So I wrote,
$scope.showNext = function(evt) {
var elm = evt.target;
$(elm).hide();
$(elm).next().hide();
$(elm).closest("div.row").next().slideDown();
};
This is not working as ng-hide is overriding my slideDown. What is the angularjs way of doing it?
Also I would like the delete button only on the $last visible row && !first. How to find last visible row in ng-repeat?
Fiddle: https://jsfiddle.net/codeandcloud/u4penpxw/
You shouldn't manipulate the DOM with things like $(elm).hide();, you should use ng-class= to let Angular add classes that hide or show the elements. If you switch your ng-repeat to ng-repeat="job in jobs track by $index", you could write something like that in your showNext()-function:
$scope.showNext = function(index) {
$scope.currentJob = $scope.jobs[index]
}
and call it like ng-click="showNext($index) - of course you'd need to do some refactoring as well. But then you could write something like ng-class="{hidden: (job == currentJob}" to hide all buttons except in the current row.
There's a lot of good thoughts in this q&a: "Thinking in AngularJS" if I have a jQuery background?

Live search in AngularJS: updating the results

I want a live search: the results are queried from web api and updated as the user types.
The problem is that the list flickers and the "No results" text appears for a fraction of second, even if the list of results stays the same. I guess I need to remove and add items with special code to avoid this, calculating differences between arrays, etc.
Is there a simpler way to avoid this flicker at least, and probably to have possibility to animate the changes?
It looks like this now:
The html part is:
<div class="list-group">
<a ng-repeat="test in tests track by test.id | orderBy: '-id'" ng-href="#/test/{{test.id}}" class="list-group-item">
<h4 class="list-group-item-heading">{{test.name}}</h4>
{{test.description}}
</a>
</div>
<div ng-show="!tests.length" class="panel panel-danger">
<div class="panel-body">
No tests found.
</div>
<div class="panel-footer">Try a different search or clear the text to view new tests.</div>
</div>
And the controller:
testerControllers.controller('TestSearchListCtrl', ['$scope', 'TestSearch',
function($scope, TestSearch) {
$scope.tests = TestSearch.query();
$scope.$watch('search', function() {
$scope.tests = TestSearch.query({'q':$scope.search});
});
}]);
You should use ng-animate module to get the classes you need for smooth animation. For each ng-repeat item that's moved, added, or removed - angular will add specific classes. Then you can style those classes via CSS or JS so they don’t flicker.
An alternative way of doing what you require is to use the angular-ui bootstrap Typeahead component (check at the bottom of the post). It has a type-ahead-wait property in milliseconds and also a template url for customising it.
<div ng-app>
<div ng-controller="MyController">
<input type="search" ng-model="search" placeholder="Search...">
<button ng-click="fun()">search</button>
<ul>
<li ng-repeat="name in names">{{ name }}</li>
</ul>
<p>Tips: Try searching for <code>ann</code> or <code>lol</code>
</p>
</div>
</div>
function MyController($scope, $filter) {
$scope.names = [
'Lolita Dipietro',
'Annice Guernsey',
'Gerri Rall',
'Ginette Pinales',
'Lon Rondon',
'Jennine Marcos',
'Roxann Hooser',
'Brendon Loth',
'Ilda Bogdan',
'Jani Fan',
'Grace Soller',
'Everette Costantino',
'Andy Hume',
'Omar Davie',
'Jerrica Hillery',
'Charline Cogar',
'Melda Diorio',
'Rita Abbott',
'Setsuko Minger',
'Aretha Paige'];
$scope.fun = function () {
console.log($scope.search);
$scope.names = $filter('filter')($scope.names, $scope.search);
};
}

Angularjs: Call bootstrap modal multiple views.

My goal is to move the modal out of my source view, and move it into its own view, but for some reason, my modal does not show up. I have tried putting the modal into a directive, but its not working. I have moved the modal to the index page, but then the view changes when they modal opens.
Category.html
<section class="row">
<h1>{{ selectedCategory | uppercase}}</h1>
<div class="col-md-3 col-xs-12" ng-repeat="source in sources[selectedCategory]">
<a ng-href="#/explore/{{selectedCategory}}/{{source.name}}">
<section class="col-xs-2">
<img ng-src="assets/img/{{source.imagename}}" height="30" width="30">
</section>
<p class="col-xs-8">{{ source.name }}</p>
</a>
<div ng-if="!objectContains(addedSources,source.name)"><!-- Show this, if addesSources does not contains source.name -->
<section class="col-xs-2">
<!-- This part, is where i want the modal to be called. -->
<button class="tiny" data-toggle="modal" data-target="#myModal" ng-click="setUpModalData(source.name)">Add</button>
</section>
</div>
<div ng-if="objectContains(addedSources,source.name)"> <!-- Show this, if addesSources contains source.name -->
<section class="col-xs-2">
<button class="tiny secondary" ng-click="removeSource(source.name)">remove</button>
</section>
</div>
</div>
</section>
<div class="modal fade" id="myModal" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<!-- Modal content -->
</div><!-- modal-content -->
</div><!-- modal-dialog -->
</div><!-- myModal -->
Currently the controller does not open or close the modal, its only job is to provide the information shown in the modal. If you click on add for a particular source, the modal will open with that source name on the top.
I have tried doing what seems to work for other people, but i cant get it to work for me.
I want to be able to call this modal from different views. You can click add on the source List view (list of all sources), and the individual source view(details about one source). There will be an add button on both views, that will both call this modal.
I am using twitter bootstrap for the css.
Here is my Controller for this view.
.controller('CategoryController', ['$scope', '$http', '$routeParams', function($scope, $http, $routeParams){
$http.get('assets/js/Category.json').success(function(data) {
$scope.selectedCategory = $routeParams.simplename; //Get the the name of the url
$scope.sources = data; //set sources list, for view to iterate.
$scope.collectionList = {}; // List of all collections, and source under every collection
$scope.addedSources = {}; // object of sources, and the collection they're in. etc ("The Verge" : tech)
$scope.setUpModalData = function(simplename){
$scope.selectedSourceName = $scope.selectedSourceNameTitle =simplename;
$scope.selectedCollection = $scope.selectedCategory;
/* if the current category does not exist in the collection list,
* we will pre fill the form with the current category.
* Other wise we will set it, and it will not be pre pubulated.
*/
if(!($scope.selectedCategory in $scope.collectionList)){
$scope.collectionName = $scope.selectedCategory;
$scope.selectedCollection = 'createNewCollection';
}
}
$scope.removeSource = function(simplename){
var collectionNameHolder = $scope.addedSources[simplename]; //The collection the source is in.
delete $scope.collectionList[collectionNameHolder][simplename]; //delete the source from both lists.
delete $scope.addedSources[simplename]
}
$scope.arrayContains = function(array, element){
return (array.indexOf(element) > -1);
}
$scope.objectContains = function(object, element){
return (element in object);
}
});
}])
Can you put that in a simplified jsfiddle? I'm not sure about what you're trying to achieve and what's not working.
In any case, if you want to have a single modal for multiple views, you could do that with a service, which job would be to open or close the modal, or with events on rootScope which would tell the modal's controller that the modal should be displayed or hidden.
https://docs.angularjs.org/guide/services#creating-services
https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$broadcast

Resources