I'd like to do something like:
<div class='row' ng-repeat='row in _.range(0,12)'>
<div id='{{row}}'></div>
</div>
but when in the controller I try:
function SetterForCatanCtrl($scope) {
$scope._ = _;
try {
var tile = document.getElementById('5');
tile.style.backgroundImage = "url('aoeu.png')";
} catch (e) {
alert(e)
}
}
getElementById returns null so how can an element's id be set using AngularJS variables?
The function SetterForCatanCtrl is run only once, when angular encounters a ngController directive while it bootstraps your app. When this happens the element you want to access from the DOM doesn't exist yet.
Doing DOM manipulation from a controller is not a good practice, directives are can solve the kind of problem you are facing. Your use case can be solved with CSS and just switching classes but I guess you want to do more than just setting a background image.
DOM manipulation from a controller
You are not asking for custom directives, so a quick solution could done using the ngClick directive and call a method that can switch images
Example HTML
<div ng-controller='ctrl'>
<div class='row' ng-repeat='row in _.range(0,12)'>
<div id='{{row}}' ng-click="click($index)">
<button>{{row}}</button>
</div>
</div>
</div>
And JS
var App = angular.module('app', []);
App.run(function($rootScope) {
$rootScope._ = _;
});
App.controller('ctrl', function($scope){
$scope.click = function(idx){
var elem = document.getElementById(idx);
console.log('clicked row', idx, elem);
};
});
So when a button is clicked you will get an id and use it to get an element from the DOM. But let me repeat, a for this use case a directive is a better choice.
JSFiddle: http://jsfiddle.net/jaimem/3Cm2Y/
pd: if you load jQuery you can use angular.element(<selector>) to select elements from the DOM.
edit: adding directive example
DOM manipulation from a directive
Using a directive is simpler, since you can just bind an event to the element the directive is applied to
HTML
<h1>Directive</h1>
<div class='row' ng-repeat='row in _.range(0,12)'>
<div id='{{row}}' my-directive>
<button>{{row}}</button>
</div>
</div>
JS
App.directive('myDirective', function(){
return function(scope, element, attr){
element.bind('click', function(){
console.log('clicked element: ', element, element.html());
});
};
});
http://jsfiddle.net/jaimem/3Cm2Y/1/
Related
I already know about ng-if and ng-show methods of showing/hiding DOM elements. In this case, however, I have about 100 div elements, each with multiple child span elements, and whenever a span is clicked, I want the parent div to hide.
Example:
<div>Display text
<span ng-click="hideThisDiv(this)">Option1</span>
<span ng-click="hideThisDiv(this)">Option2</span>
<span ng-click="hideThisDiv(this)">Option3</span>
</div>
In the function, I want to be able to do something like:
$scope.hideThisDiv = function(element){
element.$parent.$id.visible = false;
}
Using console.log(element.$parent) in this function shows, however, that there isn't a simple way to access a "visible" property of this div element. At least, not that I can see so far.
This seems like a simple concept, I'm just lacking the proper syntax or access method.
Try below code it works
var app = angular.module('myApp', []);
app.controller('MainCtrl', function ($scope) {
$scope.hideParent = function (event) {
var pEle = event.currentTarget.parentElement;
pEle.style.visibility = "hidden";
}
});
<!DOCTYPE html>
<html ng-app="myApp">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-controller="MainCtrl">
<div>
This is parent div click below to hide <br />
<span ng-click="hideParent($event)">Click here to hide</span> <br />
<span ng-click="hideParent($event)">or Here</span><br />
<span ng-click="hideParent($event)">or Here</span>
</div>
</body>
</html>
If you prefer to do this with jquery then use the jqLite approach with angular.element like this:
$scope.hideThisDiv = function(el) {
angular.element(el.target).parent().addClass('hidden');
};
Then pass in the event like this:
<span ng-click="hideThisDiv($event)">Option1</span>
The add this to your css
.hidden {
display:none
}
Solution:
The better approach is to create a custom directive and hide the parent element using jqLite.
var app = angular.module('app', []);
app.directive('hideParentOnClick', function () {
return {
link: function (scope, element) {
element.on('click', function () {
element.parent().css({display: 'none'});
});
}
}
});
And in your HTML:
<div>
Display text
<span hide-parent-on-click>Option1</span>
<span hide-parent-on-click>Option2</span>
<span hide-parent-on-click>Option3</span>
</div>
Plunker Example
Advantages:
You can combine this directive with the aforementioned ng-click because the last one is not utilized in this method and can be freely used for any other purpose.
Directives are intended for DOM manipulations, not controllers. Read more here.
Better overall modularity.
I have a div in my html. Inside the div I am invoking a controller. I need to pass some data from div to the controller. I don't have any other html element in div like input fields/buttons etc.
<div ng-controller="writeLoadTimeController">
<!--adding this controller to send the page load time to server-->
$scope.loadTime=$window.performance.timing.domContentLoadedEventEnd-$window.performance.timing.navigationStart;
</div>
How do I pass the value of the loadTime field to the controller.
you can try:
<div id="loadTime" ng-controller="writeLoadTimeController" ng-load="someFunction()">
</div>
and controller:
$scope.someFunction = function(){
$scope.loadTime=$window.performance.timing.domContentLoadedEventEnd-$window.performance.timing.navigationStart;
}
1: You can add onload event to the div and call a function which will calculate the loadTime for you. It should be like this.
you html:
<div id="loadTime" ng-controller="writeLoadTimeController">
</div>
and the controller:
app.controller("writeLoadTimeController", function($scope){
$scope.loadTime ="";
document.getElementById("loadTime").addEventListener('onload', onloadHandler);
function onloadHandler(){
$scope.loadTime=$window.performance.timing.domContentLoadedEventEnd-$window.performance.timing.navigationStart;
}
});
Then you can use {{loadTime}} in the html.
2: You can avoid adding onload listener and do the following:
you html:
<div id="loadTime" ng-controller="writeLoadTimeController">
</div>
and the controller:
app.controller("writeLoadTimeController", function($scope){
$scope.loadTime ="";
$scope.loadTimeCalculator = function(){
$scope.loadTime=$window.performance.timing.domContentLoadedEventEnd-$window.performance.timing.navigationStart;
}
$scope.loadTimeCalculator();
});
It will call loadTimeCalculator() function when the writeLoadTimeController is called.
Hope this will help you:)
I am using bootstrap and angular directives.
My angular directive template uses bootstraps class 'col-md-3' and initial rendering it works. But on page resize, my directive which renders html content is not responsive (not rearranging contents based on window size).
<div class="col-md-12">
<my-dir data-list="arrayOfObjects">
<my-card item="card"></mycard>
</my-dir>
</div>
my-dir is my first directive, which uses ng-repeat like below
<div class="col-md-3" ng-repeat="card in dataList">
<div inject></div>
</div>
inject is another of my directive which has code like below
link: function($scope, $element, $attrs, controller, $transclude) {
var innerScope = $scope.$new();
$transclude(innerScope, function(clone) {
$element.empty();
$element.append(clone);
$element.on('$destroy', function() {
innerScope.$destroy();
});
});
}
Why is bootstrap failing to work .. if instead of using directives, i directly put my code using "col-md-3" then it works.
I want to create dynamically an element when I click on a button. Do I have to use ng-click or a directive for that?
Here is a JSFIDDLE of what I'm trying to achieve using jQuery :
HTML:
<button id="myButton">Click Me</button>
<div id="container"></div>
JS:
$("#myButton").on("click", function() {
$("#container").append('<div class="box"></div>');
});
Also, here is a base JSFIDDLE, of what I have so far, to work on if you want for an angularjs solution.
Warn:
Please avoid a solution with a controller using ng-repeat. The code above is a simplified example. The created elements won't be as a list, because I'll attach a drag directive to them.
Do I have to use ng-click or a directive for that?
To create new element I would use $compile. Any DOM manipulations I strongly recommend to do in directives only. You can trigger appending process through ng-click directive or to use bind like:
element.bind("click", function(e){
// do stuff here
});
Something like that:
demo.directive("boxCreator", function($compile){
return{
restrict: 'A',
link: function(scope , element){
element.bind("click", function(e){
var childNode = $compile('<button ng-click="doStuff()" >new button</button>')(scope)
element.parent().append(childNode);
});
scope.doStuff = function(){
// do stuff
}
}
}
});
Demo Fiddle
http://jsbin.com/cuciyu/2/edit
JS
var app = angular.module('app', []);
app.directive("addDiv", function($compile){
return{
restrict: 'AE',
link: function(scope , element,attr){
element.bind("click", function(e){
var container = angular.element(document.querySelector("#container"));
var childNode = $compile('<div class="box">BOX DIV</div>')(container);
container.append(childNode);
});
}
};
});
app.controller('firstCtrl', function($scope){
});
HTML:
<body ng-app="app">
<div ng-controller="firstCtrl">
<button add-div>Click Me</button>
<div id="container"></div>
</div>
</body>
Here is my Plunker:
http://plnkr.co/edit/oIei6gAU1Bxpo8VUIswt
When the button is clicked, the following should be inserted before the "Hello World!" span:
<script type="text/ng-template" id="tempTest">
<div>
<span>Properly Inserted</span>
</div>
</script>
minus the script tags, of course.
I achieve this by dynamically inserting the following div:
<div ng-include="tempTest"></div>
And then compiling it. However, if you look at the log, the only thing that is left after the compilation is this:
<!-- ngInclude: tempTest -->
What is going on here? Why isn't my insert properly compiling? the logic is as follows:
$scope.insert = function(){
// Create elements //
var container = angular.element('<div id="compiled-container"></div>');
var element = angular.element('<div ng-include="tempTest"></div>');
//Insert parent Container
$('#greeting').before(container);
// insert the element
$animate.enter(element, container);
// test insertion
console.log("Before Compile: " +container.html() )
$compile(element);
//look again after compile
console.log("After Compile: " +container.html() )
};
The quick answer might have been:
<div ng-include="'tempTest'"></div>
Probably you just forgot the single quotes to reference the template.
The long answer:
It is not advised to access the DOM inside a controller - you will get in trouble as the code will be flooded with $scope.$apply() calls. Think about implementing this feature with a directive. I tried to create a starting point from your code here
http://plnkr.co/UWUCqWuB9d1dn6Zwy3J3
var app = angular.module('plunker', ['ngAnimate']);
app.directive('greeting', function($compile){
return {
restrict: 'E',
scope: {
name: '='
},
template: '<div>'+
' <span>Hello {{name}}!</span>'+
' <button ng-click="insert()">test</button>'+
'</div>',
link: function(scope, element, attrs) {
scope.insert = function() {
var container = angular.element('<div ng-include="\'tempTest.html\'"></div>');
element.before($compile(container)(scope));
}
}
}
})
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
});
<greeting name="name"></greeting>
The template elements are inserted before the Hello World! textnode everytime the button is clicked.
Side note You dont even need the scope{ name: '='} as the directive will inherit its surrounding scope, but its the cleaner way to pass (actually bind) controller variables to a directive explicitly.
<div ng-include src="tempTest"></div>
This should work
^^^ note that this will NOT even begin to work unless single quotes are added (as #JHixson has already pointed out), like so:
<div ng-include src="'tempTest'"></div>
Simply your script :
<script type="text/ng-template" id="tempTest">
<div>
<span>Properly Inserted</span>
</div>
</script>
Must be inside the MainCtrl controller selector like this :
<div ng-app="plunker" ng-controller="MainCtrl">
<script type="text/ng-template" id="tempTest">
<div>
<span>Properly Inserted</span>
</div>
</script>
</div>