I try to make tabs with Angular bootstrap.ui Tabs. Static tabs work, but dynamic don't show title and content. Below my code:
My JS:
(function (angular) {
angular.module('numeter', ['ui.bootstrap']).
controller('configurationMainTabCtrl', ['$scope', '$http', function ($scope, $http) {
$scope.maintabs = [
{ title:"Users", content:"Test", url:"/user" },
{ title:"View", content:"", url:"/view" },
];
}]);
}(angular));
My HTML:
...
<div ng-controller="configurationMainTabCtrl">
<tabset maintabs>
<tab ng-repeat="maintab in maintabs">
<tab-heading>{{maintab.title}}</tab-heading>
{{maintab.content}}
</tab>
</tabset>
</div>
...
This code show me empty tabs selectable with empty content.
Since you didn't include all your code, I'm not sure if this was the problem, but in future it'd be mighty helpful if you linked to a plunker or fiddle. That way, we can see the code in action, and it's also easier to fork that with the solution. (Plus I find plunkers handy for narrowing down things to just the exact code I'm working on, which helps me troubleshoot.)
Here's a plunker with your code, edited: http://plnkr.co/edit/u80OhmN7YqYRytFE7kG5?p=preview
When using your setup, the only error I got was that it couldn't see your controller as a function, which means it's not picking up on the ng-app. As soon as I add ng-app="app" to the body tag, everything started working. Since I've only got the code you posted, I'm not sure, but that might've been one problem.
The other possible culprit might be these two lines:
<tabset maintabs>
<tab ng-repeat="maintab in maintabs">
change them to this:
<tabset>
<div ng-repeat="maintab in maintabs">
and then things should be behave. Otherwise you've got ng-repeat on the tab directive, when the directive expects just one tab per, well, tab. Put the part inside the ng-repeat, not alongside it, I mean.
Not sure if its relevant to your case, but I had the same issue in a different scenario. If you are using ng-include like this <div ng-include="'mytemplate'" ng-controller="MyCtrl"></div>, then there is a scoping problem somewhere between 1.1.6 and 1.2.2 which might explains why you might not be seeing maintabs.
Thanks for all your responses.
It was a noob mistake. I use Django and {{...}} are evaluated by Django template system. I add {% verbatim %} tag to escape angular part and it works.
Related
In my AngularJs Project I have a DIV tag which contains the main navigation bar in my project.
This navigation bar has it's own specific controller which called "topNavController".
I've recently modified my app in order to load everything -somehow- lazily using RequireJs .
The problem is this controller is not dependant on any view/route and has to be loaded directly after my App.js loads .
I'm bootstrapping my app from my RequireJs main file using :
angular.bootstrap(document, ['myApp']);
If I do like :
<div ng-controller="topNavController">...</div>
I get an error which says :
Argument 'topNavController' is not a function, got undefined
which I think it's because myApp is not bootstrapped at the moment Angular tries to bind this controller to my DIV.
I appreciate any suggestions, workarounds or solutions for this.
Thanks in advance.
You miss ng-app to launch the angular bootstrap method.
<div ng-app="myApp">
<div ng-controller="topNavController"></div>
</div>
You should use directive for this behavior
I've fixed it by removing
ng-controller='topNavController'
and making a directive for it, I put all the code from topNavController to topNavDirective and used directive's controller instead.
Thanks to "iScor" hint in the answer above !
here is how the last version of my main RequireJs file looks like :
require(
[
'app',
'routeResolver',
'services/authService',
],
function () {
require(["directives/topNavDirective"]);
angular.bootstrap(document, ['myApp']);
});
I have some articles of the same category and I'm routing like this:
app.config(function($routeProvider) {
$routeProvider
.when('/chapter/:title', {
templateUrl: 'article.html',
controller: 'article'
});
});
article.html:
<h1>{{title}}</h1>
<p>{{content}}</p>
<button>Editor</button>
But now I want to get a route from every article of this chapter to an editor version to change the content. This editor-version could look like this:
editor_article.html:
<input type="text" value="{{title}}">
<textarea>{{content}}</textarea>
So what is the best way for routing the button of an article to the editor_article.html-template and load it with the same data?
There is no "best-way" here, and it all depends on your context.
Do all end-users have equal access to this (or put another way, should anybody who can open the dev-console be allowed to access this page)?
If not, you need to solve the login problem before you load most of the code for your SPA.
If login isn't a problem, or already taken care of, why do you need separate routes?
Do you need to cache these pages separately in-browser?
Are there other considerations beyond that?
Totally legitimate question; from an artistic perspective, perhaps you're hoping for page transitions which match other transitions you have for when you do change routes, or you are relying on routeParams for some logic that we don't know about.
But chances are good that all of the above things aside, you could simply have a button and a couple of ng-if statements, with directives.
<body >
<main ng-view></main>
</body>
<!-- template -->
<section >
<button
ng-click="article.toggleMode()">{{
article.editMode ? "View": "Edit"
}}</button>
<article-view
content="article.content"
ng-if="!article.editMode"
></article-view>
<article-edit
content="article.content"
onsave="article.save(content)"
ng-if="article.editMode"
></article-edit>
</section>
Using directives to define the two templates, using controllerAs:"article" in the example above.
Even that might be complicating it.
I try to follow an example from http://blog.novanet.no/creating-multilingual-support-using-angularjs/
to make multilingual support using AngularJS. This example works well.
I try another way to implement that. I use ng-include to manage module separation of the header, content and footer by using the AngularJS ng-include.
My HTML structure is like this:
<div ng-include = "'header.html'"> </ div>
<div ng-include = "'content.php'"> </ div>
<div ng-include = "'footer.html'"> </ div>
I save my work on Plunker
My question is, when I try to implement multi-language, and put the selector of language in header.html and the result on content.php it is not working.
When your templates create models, they do so on the current scope, which isn't shared with your controller scope (as mentioned in a previous answer, ng-include creates a new child scope). Because of the way inheritance works, items added to this child scope are not visible to the parent (or siblings).
However, If you add items to an item already on the parent scope (google "dot notation angular"), those additions will be visible to the parent and siblings.
A good way to do this is use the controller-as syntax. I've updated your Plunk
<body ng-app="myApp" ng-controller="myController as vm">
app.controller('myController',['$scope', 'translationService',
function ($scope, translationService){
//Run translation if selected language changes
$scope.translate = function(){
translationService.getTranslation($scope, $scope.vm.selectedLanguage);
};
//Init
$scope.vm.selectedLanguage = 'en';
$scope.translate();
}]);
I've discovered that when I use ng-include it gets called far too often.
Every time you click one of the Nothing buttons or change Views, or type something in the input box, getView gets run several times. Up to 6 times when changing views. Basically doing anything that alters the $scope will generate a call to getView.
I've created a plunker to show the behavior I'm describing: plnkr.co
Is this normal behavior and is there any way to make it only run once? I'm worried I may be losing performance due to this.
MY CODE:
index.html
<body ng-app="includeExample">
<div ng-controller="ExampleController">
<div class="row">
<input type="text" ng-model="unrelated">
</div>
<div class="row">
<tabset>
<tab heading="View 1">
<ng-include src="getView('template1')"></ng-include>
</tab>
<tab heading="View 2">
<ng-include src="getView('template2')"></ng-include>
</tab>
</tabset>
</div>
</div>
</body>
Script.js
angular.module('includeExample', ['ngAnimate', 'ui.bootstrap'])
.controller('ExampleController', ['$scope',
function($scope) {
$scope.getView = function(filename) {
console.log("getView " + new Date());
return filename + ".html";
};
}
]);
Template1.html
Content of template1.html
<button type="button" class="btn btn-primary" ng-click="">Nothing</button>
Angular is calling your getView method each time a digest runs to make sure the value hasn't changed. This is part of the "magic" for how angular binds the model and the view together. If you look at the network tab for your development tools you will see that the template is not actually being retrieved by the browser each time the digest runs. Knowing that this is how the digest actually works - you should develop code accordingly running intensive operations in methods that are not directly bound to the view!
For more information on the digest itself see:
http://angular-tips.com/blog/2013/08/watch-how-the-apply-runs-a-digest/
https://docs.angularjs.org/guide/scope (search for "Scope Life Cycle")
https://www.ng-book.com/p/The-Digest-Loop-and-apply/
Hope that helps!
Yeah, angularJS will go through getView() every time you do anything. A good first iteration would be to assign it to a json object instead of using a get method. Actually, it's better if you don't use any get type methods in the html. Then if you really want it to not change, you can remove the 2 way binding (Render value without data-binding).
I uses angular ui tab (http://angular-ui.github.io/bootstrap/) and I added a delete btn inside the the js file. I can't do it with my markup because the js generate the template on the js side.
my ng-click doesn't work when I put this
<span ng-click="deleteTab()" >dlt</span>
js
$scope.deleteTab = function(){
//$scope.tabs.splice(this, 1);
alert('d');
}
within my controller. I tried to include the js on the topest and before the , nothing work. Until I try onClick. I wonder why I can't use ng-click in my situation?
If you add new HTML to the DOM without using angular, you need to $compile the HTML to let angular to bind the content and $watch changes. See the docs
$compile(element.contents())(scope);
Edit:-
Ah you can give the title as a HTML template as well,see the tabs definition
<tab ng-repeat="workspace in workspaces"
active=workspace.active>
<tab-heading>{{workspace.name}}<span ng-click="deleteTab()" >dlt</span></tab-heading>
<div ng-controller="TabsChildController" >
<div>
{{workspace.id}} : {{ workspace.name}}
</div>
<input type="text" ng-model="workspace.name"/>
</div>
</tab>
and here is the solution
that's a plunker that could solve your problem.plunker the only doubt is what workspace would you want to close, i imagine it is the last, otherwise you only need to modify the delete method.
EDIT
in this version you can delete the selected workspace, you have to controll the css, but i thin it could be a good solution
new plunker