Tab's content overlaps its neighbour's tab's content - angularjs

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"

Related

changing md-selected with md-tabs and using md-button (prev, next)

I am experiencing a strange behavior when switching tabs using different methods of changing the tab index. I can change md-selected using the $scope.changeQuestion function with ng-click. I can also use the built in clicking of the md-tab to change md-selected. The issue lies when I click the md-tab and then try to click my prev or next buttons that utilize the $scope.changeQuestion function. If I click the tabs and then try to use my buttons to change the index, the buttons don't change the tab index anymore. They do log the appropriate index I want to switch to, however.
controller
$scope.changeQuestion = function(index){
$scope.selectedQuestion = index;
};
html
<md-tabs md-selected='selectedQuestion' md-stretch-tabs md-dynamic-height md-border-bottom>
<md-tab ng-repeat='question in assessment.questions | toArrayKeepKeys | orderBy: "order"'>
<md-tab-label>
{{question.order}} <i class="fas fa-fire fire" ng-if='question.bonus'></i>
</md-tab-label>
<md-tab-body>
<div class='question-tab-content'>
<question class='margin-top-1em' details='question' answer='answers[question.key]'></question>
<div>
<md-button ng-click='changeQuestion($index - 1)' ng-hide='question.order === 1' class='md-primary md-raised no-left-margin'>Previous</md-button>
<md-button ng-click='changeQuestion($index + 1)' ng-hide='question.order === _.size(assessment.questions)' class='md-primary md-raised no-left-margin'>Next</md-button>
</div>
</div>
</md-tab-body>
</md-tab>
</md-tabs>
Here is the example of the behavior:
I was able to get a working example in codepen but can't seem to get it to work in my project.
Update
Tried putting a $watch on $scope.selectedQuestion and it doesn't fire if I click the tabs. It's like the md-selected='selectedQuestion' and $scope.selectedQuestion are different but only after I click a tab.
Found Solution: scope inheritance
Changing $scope.selectedQuestion = 0; to $scope.selectedQuestion = { selected: 0 }; and updating other references did the trick.
Unexplained: why the codepen example works without the modifications from the solution

Bootstrap Tab Clears My Model when Hidden

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.

AngularJs + MVC: How to populate page view from a clicked link in shared layout view?

I'm very new to AngularJs & working on a test project using AngularJs + MVC, so apologies if this code looks very botched.
I'm trying to figure out how to make a clicked link in my shared view pass over to my index.cshtml view, in a manner that my index view will know which link was clicked. Ideally, I'd like to do this with angular, so it's seamless. In my MVC project, I created a shared view for my website template. Within this template, is a dropdown, populated via AngularJs after retrieving values from my database. The dropdown contains links on each item within the dropdown. When a user clicks one of the dropdown links, I want to pass the call seamlessly to my index.cshtml view, but I'm not sure on the best way to do this.
Here's the code I have so far, which is retrieving all dropdown values from the database & populating them in my dropdown on my shared view template. This works fine, but now I'm unsure of what to do when a user clicks a link within the dropdown. What I need to happen, is for the table data on my index view to change, based on which link the user clicks in the dropdown.
In my shared view, I'm populating my dropdown values (campaign.Campaign1) via Angular. "SelectedCampaign" is just text of the campaign name that the user's currently selected:
<div style="text-align:center">
<div class="btn-group" ng-controller="menuController">
<button type="button" class="btn btn-danger">{{SelectedCampaign}}</button>
<button type="button" class="btn btn-danger dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
<span class="caret"></span>
<span class="sr-only">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu" role="menu">
<li ng-repeat="campaign in campaigns">
{{campaign.Campaign1}}
</li>
</ul>
</div>
</div>
In my Angular MenuController.js script, I'm calling an MVC controller called "GetCampaigns", then returning the result to my shared view's dropdown:
angular.module('dashboardApp', [])
.controller('menuController', function ($scope, $http) {
$http.get('/Account/GetCampaigns')
.success(function (result) {
$scope.SelectedCampaign = result[0]['Campaign1'];
$scope.campaigns = result;
})
.error(function (data) {
console.log(data);
});
})
Thanks for any help you can provide.
Instead of using the "a" link use ng-click and use the ng-click directive to update the current data to the selected campaign data. So put all the campaigns on your scope, then use the ng-click to call a function to select the campaign. Something like:
<li ng-repeat="campaign in campaigns">
<span ng-click="selectCampaign($index)">{{campaign.Campaign1}}</span>
</li>
You can use $index to get the index in the repeat and use that to target the item in the array: https://docs.angularjs.org/api/ng/directive/ngRepeat
e.g.
$scope.selectCampaign = function(index){
$scope.selectedCampaign = $scope.campaigns[index];
}

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?

AngularJS with ui-router ng-hide not working after initially working

I've been struggling with a ng-hide issue in combination with using ui-router. Simple app. Index.html shows some data via the "notes" route, you click on "detail" and you go to the sub route "notes.note" to view the detail just below the other records. The "detail" html has a "Save" & "Cancel" button.
Now there is an "Add New" button when you are not viewing the detail with the attribute ng-hide="HideAddNew". "HideAddNew" is a $scope variable in the controller. When I click "detail" on a row I have this ng-click="toggleAddNew()" on the link which in turn calls this
$scope.toggleAddNew= function()
{
$scope.HideAddNew=($scope.HideAddNew ? false : true);
}
That works perfectly, my detail shows and my "Add New" button has disappeared. Now on the detail when I click "Cancel" it fire off the ng-click="hideData()" which calls the function:
$scope.hideData=function()
{
$scope.toggleAddNew();
$state.go('notes');
}
And now my "Add New" has disappeared even though the variable is set to false, i.e. Don't hide. I've tried $timeout in that "hideData" function and in the "toggleAddNew" function. I've tried putting "$scope.toggleAddNew();" after the "$state.go('notes');" too. I don't want to resort to manually adding and removing classes. AngularJS ver: v1.3.15 , ui-router ver: v0.2.13 Thanx all :)
EDIT
Would the below work Tony?
<button ng-if="HideAddNew" ng-click="SelectRoute('notenew')" class="btn btn-primary">
<span class="glyphicon glyphicon-plus -glyphicon-align-left"></span>Add New</button>
Perhaps you could simplify and use ng-switch instead.
Something like this:
<ul ng-switch="expression">
<li ng-switch-when="firstThing">my first thing</li>
<li ng-switch-when="secondThing">my second thing</li>
<li ng-switch-default>default</li>
</ul>
Alternatively, maybe you could use ng-if or ng-show instead of ng-hide, eg:
<p ng-if="HideAddNew">it's here!</p>
<p ng-if="!HideAddNew">it's not here.</p>
Edit
If I understand what you're trying to achieve exactly, I would use ng-show with an ng-click:
Controller:
$scope.addNew = false;
View:
<button ng-show="!addNew" ng-click="addNew = true">Add New</button>
<button ng-show="addNew" ng-click="save()">Save</button>
<button ng-show="addNew" ng-click="addNew = false">Cancel</button>
Example

Resources