So I was converting a button group to a Bootstrap Tab and then one of my views stopped appearing. I could not figure out what I had done wrong but I think I've narrowed it down to the Tab resetting my model when the Tabs are hidden. Here's what I have:
controller:
$ctrl.$onInit = function() {
$ctrl.states = [ // for toggling which view to display
'state0', // 0
'state1', // 1
...
];
$ctrl.currentState = $ctrl.states[3]; // this should show my forth view
};
View:
<!-- setting to false for testing -->
<div class="panel-body desktop hidden-xs hidden-sm" ng-show="false">
<!-- here I use currentState to determine which one is active -->
<uib-tabset active="$ctrl.currentState" type="tabs" justified="true">
<uib-tab heading="Some Text" index="'state0'">
<div class="text-center text-primary">Fields Marked With * Are Required.</div>
</uib-tab>
...
</uib-tabset>
</div>
When the tabs are being hidden currentState gets set to "" and my other view doesn't display.
View2:
<div class="panel-body" ng-show="$ctrl.currentState === 'state4'">
...
<div>
How can I disable this behavior? I've done some research but I haven't found anyone with this issue. Thanks in advance.
I guess no one else has encountered this issue. I have found a work around though.
I added a new tab that I don't display.
<uib-tab heading="Some Text" index="'state4'" ng-show="false">
</uib-tab>
Since a tab exists now for this state my currentState variable doesn't get cleared. I'd love a better answer for this but it's at least functional now.
Related
Let me explain the issue with the help of the following example:
I added 3 tabs e.g. TAB1 , TAB2 and TAB3. Now If I delete TAB2, the
remaining tabs will be TAB1 and TAB2 (as TAB3 will take TAB2 place
now). Now, when I add a new tab e.g. TAB3, I will see 2 tab's contents
at the same time. One which tab was newly created and second which tab
was right behind the newly created tab.
I monitored the HTML at the time of addition and deletion of the tab by inspecting and also checked array's index values they were changing fine.
As far I could detect, the cause of it is that the content tab of the newly added tab is actually getting static "active" class which does not changes.
I guess ui.bootstrap is the causing this issue.
I'm using the following code to make tabs functionality I need.
HTML code is:
<uib-tabset active="activeForm">
<uib-tab index="$index + 1" ng-repeat="tab in $scope.tabs" heading="{{tab.title}} {{$index+1}} " active="{{tab.active}}">
{{tab.content}}
<button type="button" class="btn pull-left btn-primary" ng-click="removeTab($index);">
Delete this wave
</button>
</uib-tab>
<button type="button" class="btn" ng-click="addNewTab();">
+
</button>
</uib-tabset>
And js code is:
$scope.tabs = [
{ title:'TAB'+($scope.tabs.length+1), content:'This wave of contacts will be activated before all other waves of contacts.', active:true }
];
$scope.addNewTab = function() {
$scope.tabs.push(
{
title:'TAB'+($scope.tabs.length+1), content:'Content for tab new tab.'
});
$scope.removeTab = function(index) {
if($scope.tabs.length>1) {
$scope.tabs.splice(index, 1);
}
};
}
One more thing, I'm totally new to both AngularJS and angular ui.bootstrap. So, please treat me as a beginner.
you must use "track by $index" in ng-repeat if you are using $index in your logic (html)
e.g ng-repeat="tab in $scope.tabs track by $index"
I am studying AngularJS by looking at the website http://campus.codeschool.com/courses/shaping-up-with-angular-js/contents and downloaded the videos, then going through the examples on my computer.
Everything went well until the video codeschool_1329.mp4, otherwise called "Shaping_Up_With_Angular_JS_Level_2b". The example works correctly when the logic for selecting the panels is in the HTML code, but when the logic is moved to a controller, it no longer works correctly. Thus I have the relevant HTML code:
<section ng-controller="PanelController as panel">
<ul class="nav nav-pills">
<li ng-class="{active:panel.isSelected(1)}">
<a href ng-click="panel.selectTab(1)">Description</a>
</li>
<!-- Repeated for Specifications and Reviews -->
</ul>
</section>
<div class="panel" ng-show="panel.isSelected(1)">
<h4>Description</h4>
<p>{{product.description}}</p>
</div>
<!-- Repeated for Specifications and Reviews -->
and for the JavaScript code I have:
app.controller('PanelController', function(){
this.tab = 1;
this.selectTab = function(setTab){
this.tab = setTab;
};
this.isSelected = function(checkTab){
return this.tab === checkTab;
};
});
exactly as in the video. The latter is with the Angular module and another Angular controller for the store.
With both Google Chrome and Firefox, when I click on the each of the tabs "Description", "Specifications" and "Reviews", the selected tab is highlighted, as in the video, albeit blue rather than dark purple, but the text that is supposed to be displayed below the selected tab does not show up at all. It looks as if there is some type of a problem with the isSelected function in PanelController with ng-show="panel.isSelected(1)", etc. in the lower part of the HTML code, although it appears to work correctly with ng-class="{active:panel.isSelected(1)}" when the tab is highlighted.
This works correctly when the logic for this is in the HTML code, as I said above, but no matter what I can do, I am unable to get this to work correctly when the logic is in PanelController.
There must be something simple that I am missing, and would be grateful to get this sorted out - many thanks.
<section ng-controller="PanelController as panel">
...
</section>
<div class="panel" ng-show="panel.isSelected(1)">
Only the section element is controlled by the panel controller, but you're trying to use panel.isSelected(1) out of that section. So that can't work.
Put the div inside the section, or wrap everything with another div and move ng-controller="PanelController as panel"to that wrapping div.
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?
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
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)