I have a tabbed navigtion in my webapp that looks like this
Now I want to Change the directive each time the user clicks on one of the Navigation points. My Idea was to init the page with the first template.
$scope.currentDirective = $compile('<div order-Sale></div>');
Then when the user clicks on a tab, I wanted to change and compile the content again with a new directive in it. But for some reason this is not working. How would you proceed in order to archive this dynamic content loading? I really want to only load the content on necessary need and not just to show or hide it. I think using directives is the right way to go for it, but I'm a but stuck at the implementation... Someone any pointer ? (I don't want to use any jQuery)
What I tried [Edit]:
The controller.js
app.controller('pageController',['$scope','$compile', function($scope, $compile){
var templates = ['<div first-template></div>','<div second-template></div>'];
$scope.currentTemplate = $compile(templates[0]);
$scope.changeTemplate = function(id) {
$scope.currentTemplate = $compile(templates[id]);
};
}]);
The HTML
<div ng-controller="pageController">
<li>
<a ng-click="changeTemplate('1')">Change Template</a>
</li>
{{currentTemplate}}
</div>
UPDATE
$compile returns a linking function not a value, you cannot just bind it to your template with interpolation.
You should use ngBindHtml instead of regular bindings ( ngBind & {{ }} ).
ngBindHtml does compiling, linking and watching all out-of-the-box.
With ng-bind-html-unsafe removed, how do I inject HTML?
Here is a plunker
app.controller('pageController',['$scope','$compile','$sce', function($scope, $compile, $sce){
var templates = ['<div>first-template</div>','<div>second-template</div>'];
$scope.currentTemplate = $sce.trustAsHtml(templates[0]);
$scope.changeTemplate = function(id) {
$scope.currentTemplate = $sce.trustAsHtml(templates[id]);
};
}]);
The markup:
<div ng-controller="pageController">
<button ng-click="changeTemplate('1')">Change Template</button>
<div ng-bind-html="currentTemplate"></div>
</div>
For more robust dynamic content loading you have two good alternatives:
ngRoute from angular team.
ui-router from angular-ui team.
If you want to change and compile the content again, well that's exactly what ng-view/ ui-view directives already do for you.
Why not just use a directive:
You probably need to load a different template (html partial) for each tab.
You probably need to change the url based on the tab (and vice versa)
You probably need to instantiate a different controller for each tab.
ngRoute and ui-router come with their own directives.
You can implement your own route module if you want but that's more than just a directive.
Related
I have an angluar module.
In that module I have a controller with a function.
I need to execute that function in popup on href click.
As the popup content is not initially part of DOM or angular context, how can make a angular function to be executed by that generated code?
Here is what I try to code: codepen
app.controller('AppCtrl', ['$scope', 'myPopup', function($scope, myPopup) {
...
var infoWindow = new google.maps.InfoWindow({
content: "<a href='#' onclick='myPopup.show();'>this is my link</a>"
});
To retain is that I don't try to make execute exactly this code, I just search a way to execute an angular service function from a generated "on-fly" html code (a dynamic popup content, in my case).
First of all here's the working codepen: http://codepen.io/anon/pen/vKRWYy?editors=1010
So, the solution(just A solution. Not THE solution) is to add modal open function on window or global scope. And invoke that function on clicking the map.
window.showPopup = function(){
myPopup.show();
};
<a href='#' onclick='showPopup();return false;'>this is my link</a>
On a side note, it's generally not good practice to use non angular code with angular. It might be worth looking at an angular google maps implementation like: http://angular-ui.github.io/angular-google-maps/#!/. Maybe?
Been struggling on how to tie angular with CSS animations... I'm sure I'm not getting something fundamental.
My goal is to have a list of search results. When you click one, a detail view will slide out from under the list. When you click another, the old detail view slides back, the details for the new one load, and then the detail view slides back in.
I don't have any code to show that even remotely works, but if anyone can point me at an example or offer some basic code, I would be extremely grateful.
Thanks!
You want to use ng-animate for animations.
ng-animate essentially adds CSS classes to elements automatically (often for a short time) during, for example, state transitions, during the population of an ng-repeat, etc.
You do not add the CSS classes to elements yourself this is done by ng-animate.
You do, however, apply the styling for those class in your style-sheet.
Its up to you, in your CSS, to do something with those automatically added CSS classes. Typically, you might want to do a fade in using CSS transitions.
For example ... https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions
OR
http://www.nganimate.org/
The ng-animate link details exactly which classes are added when. There are too many to mention here.
You might also want to use ng-fx
ng-fx github is here https://github.com/AngularClass/ng-fx
ng-fx requires ng-animate
ng-fx can be seen at work on its demo page - http://hendrixer.github.io/
This should get you going :)
I would go with ng-show.
var myApp = angular.module('myApp',[]);
myApp.controller('SomeController', ['$scope', function($scope) {
//this can be a service with a ngResource, an ajax call using $http... this is a baaaaasic dummy example.
$scope.yourScopeFunction = function(){
$scope.data = '';
$scope.data = {};
$scope.data.param1 = 'Hello';
$scope.data.param2= 'Jhon';
}
}]);
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</head>
<body ng-app="myApp" ng-controller="SomeController">
<div >
<div class="elementClass" ng-click="yourScopeFunction()">Element1</div>
<div class="elementClass" ng-click="yourScopeFunction2()">Element1</div>
</div>
<div class="yourClass" ng-show="data != ''">
<div>{{data.param1}}</div>
<div>{{data.param2}}</div>
</div>
</body>
Then, when the ng-show's expression evaluates to true (the data variable has some content), Angular will attach a new class to your yourClass element called
.ng-hide-add and when it evaluates to false, Angular will add the class .ng-hide-remove.
You just have to make the transition (or animation you want) based on the classes your element will have in both those moments. Like in the documentation example.
Something like:
.yourClass.ng-hide-add{
//some transition or animation css
}
.yourClass.ng-hide-remove{
//some transition or animation css
}
Note that my function on the example does a $scope.data = ''; so the angular ng-show expression evaluates to false and the .ng-hide-remove is added.
By the way, you will need to add Angular Animations library.
I am new to Angular JS. What I am doing is to bind ui-sref on JQuery loaded data.
All the JQuery plugins and rest of Angular is working perfectly fine. What I have for now looks like:
app.controller("FeedController", ['$scope', '$http', '$compile', function($scope, $http, $compile) {
var feed = this;
feed.years = [];
feed.getYears = function() {
$http.get('/timeline/years').success(function(data) {
feed.years = data;
});
};
feed.getYears();
$scope.$watch('sliderWrapper', function() {
applyTreemap(); // jquery treemap layout plugin
applyKnob(); // jquery knob plugin
});
// I was trying to compile externally loaded DOM by that plugin here.
// Didn't figure out how to do it.
$scope.refresh = function() {
// #slider is main content wrapper
$compile( $("#slider").html())($scope);
};
}]);
Please don't suggest to use AngularJS instead of JQuery. Actually this is a Treemap Layout plugin and already integrated into existing website.
Okay so $compile works as in my code but there are some problems I faced. Here's one. Consider the following code.
<div id="slider">
<div ng-repeat="slide in slides">
<!-- html loaded by jquery ajax will go here -->
</div>
</div>
In angular I was doing
$compile( $("#slider").html())($scope);
So, I was compiling html of #slider in angular and it already has angular bindings besides ajax loaded content. So angular compiler will re-render them and you will run into problems.
So keep in mind that you never $compile html that already has angular bindings.
So I solved my problem by putting
href="#/path/to/state"
instead of doing
ui-sref="home.child()"
into ajax loaded conent.
Sometimes you know something and its not in your mind when you are stuck. :-D
How can a html element outside of a controller communicate with a given controller ?
The situation is as following:
<button name="search">Search</button> --> in an existing layout provided by an existing framework
<div ng-app ng-controller="overviewCtrl">
<div ng-view>/div> --> this one gets a specific controller
</div>
<button name="search">Search</button> --> in an existing layout provided by an existing framework
I don't have control on the location of the button outside of the controller.
I can put attributes on it and I want to put an ng-click attribute.
It also fall outside the ng-app.
I could put a controller on it. But then I need a way to have a reference to the same controller.
What is the best way to do this ?
One way to do this is to use JQuery inside the Angular controller to bind the element outside the ng-app to a scope function through JQuery selector and click event.
You don't have control over its position, but you do have control over its rendering in some way? You say you could put an ng-click on it?
I ask because there's an easy dodge here if that's true. You could make a simple directive that's basically a "smart ng-click". Your issue with ng-click is really that it's hard to route its call into your controller because the button is elsewhere. What you need, then, is just a way to bridge the two.
It would look something like this:
angular.module('myApp', [])
.controller('MyController', ['$scope', '$rootScope', function($scope, $rootScope) {
$rootScope.$on('SearchButtonClicked', function() {
// I will be called whenever the search button is clicked...
// and I am in my controller!
});
}])
.directive('notifySearchClick', ['$rootScope', function($rootScope) {
return {
restrict: 'A',
link: function($scope, iElement) {
iElement.bind('click', function() {
$rootScope.$emit('SearchButtonClicked');
});
}
};
}]);
Working Plunkr demonstrating this concept here:
http://plnkr.co/edit/dKuDl5?p=preview
The jQuery way is also perfectly valid but then you're back to the "what mystery event handlers are on THIS element" situation. It works, and it's reliable... but if you want to keep to the AngularJS philosophy, using a directive like the one above gives you a lot of flexibility.
Note that in the Plunkr reference above I added a tiny bit of sophistication. In that example I made the message name an attribute. You could thus use a single directive for any other cases like this in the future. Just put the message name into the attribute, like this:
<button notify-click="MyButtonNameClick"></button>
I am new to angularjs, and I have an jquery background.
I want to compile json from the server into an element with an template.
What I now have for so far is:
The template:
<script type="text/ng-template" id="/tiles.html">
<div ng-repeat="tile in tiles">
{{tile.name}}<img ng-src="tile.src" />
</div>
</script>
The button for displaying the content:
<button ng-click="imageOptions.addFromList()">+ Add Image from list</button>
The function:
$scope.imageOptions.addFromList = function (){
$http
.get('/json/Tiles/get')
.success(function(data){
$scope.tiles = data;
console.log(data);
})
.error(function(data){
console.log("something did go wrong");
});
$(".prompt").html('<div ng-include src="/tiles.html"></div>');
};
The placeholder:
<div class="prompt"></div>
The placeholder will be used many times with also other content.
So I can not just type the html from the .html() argument. Like this:
<div class="prompt"><div ng-include src="/tiles.html"></div></div>
When I inspect the .prompt div it will stay uncompiled
The first thing you should do is remove jQuery library from your app while you get familiar with angular methodology.
There is no need to use html() method when all you need to do is include your template through a variety of different ways in your html source.
If the data isn't already available for ng-repeat it will simply fail quietly and do nothing. Then when the data is available it will respond automatically.
You could simply do:
<div class="prompt" ng-include src="/tiles.html"></div>
Or you could make a simple directive that will accomplish the same thing .
app.directive('prompt', function() {
return {
restrict: 'C',/* use for "class" */
templateUrl: '/tiles.html'
}
});
Simply change this
<div ng-include src="/tiles.html">
to this
<div ng-include src="'/tiles.html'">
While coding your single page application in angularjs, ideally there should not be any need for you to first get a reference to an element and then perform some action on it (You may think of this as the first step of switching from a jquery background to angularjs domain).
To achieve complete separation of model, view and controller you should just define your templates and controllers accordingly. These mappings and references should be managed by angularjs on its own.
As correctly mentioned above you should not be using .html() method of jquery. If you have included jquery in your document, it will be internally used by angularjs, but, including jquery should not be mandatory for using angularjs.
ng-repeat and ng-include also create a separate scope, so you may want to take care of those as well in future.
For your query, you may reference the template by including extra quotes in ng-include as:
<div class="prompt">
<div ng-include src="'tiles.html'"></div>
</div>
http://jsfiddle.net/PKKp8/