html"
<div id="parent">
<input type=button ng-click="getWidth()">
</div>
js:
function Ctrl($scope) {
$scope.getWidth = function(){
// How to get div[id=parent] width here?
}
}
So my question is how to get parent div in getWidth method?
like hansmaad's answer, you better use directive for handling DOM stuffs.
app.directive('getWidth', ['$timeout', '$location', function($timeout, $location) {
return {
scope: {
callbackFn: "&"
},
link: function(scope, elem, attrs) {
scope.callbackFn({width: elem[0].clientWidth});
}
}
}]);
in html
<body ng-controller="MainCtrl" >
<div get-width callback-fn="returnWidth(width)" style="height:100%; width: 100%;">
<p >Hello {{name}}!</p>
</div>
</body>
working example here
use $event.target to get the element click and then use jquery to find width
function SimpleController($scope) {
$scope.width = 0;
$scope.getWidth = function($event) {
// How to get div[id=parent] width here?
$scope.width = $($event.target).parent().outerWidth();
}
}
#parent{
background-color : red;
width : 200px
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.js"></script>
<div class="container" ng-app="" ng-controller="SimpleController">
<div id="parent">
parent width : {{width}}
<button type=button ng-click="getWidth($event)"> find width </button>
</div>
</div>
Related
I am trying that on a button click, a div and and input tag are created and the input tag contain ng-model and the div has binding with that input.
Kindly suggest some solution.
You can create the div and input beforehand and and do not show it by using ng-if="myVar". On click make the ng-if="true".
<button ng-click="myVar = true">
In controller : $scope.myVar = false;
$scope.addInputBox = function(){
//#myForm id of your form or container boxenter code here
$('#myForm').append('<div><input type="text" name="myfieldname" value="myvalue" ng-model="model-name" /></div>');
}
Here is another solution, in which there's no need to create a div and an input explicitly. Loop through an array of elements with ng-repeat. The advantage is that you will have all the values of the inputs in that array.
angular.module('app', [])
.controller('AppController', AppController);
AppController.$inject = ['$scope'];
function AppController($scope) {
$scope.values = [];
$scope.add = function() {
$scope.values.push('');
};
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="AppController">
<button ng-click="add()">Click</button>
<div ng-repeat="value in values track by $index">
<input type="text" ng-model="values[$index]"/>
<div>{{values[$index]}}</div>
</div>
<pre>{{values}}</pre>
</div>
UPDATE. And if you want only one input, it's even simpler, using ng-show.
angular.module('app', []);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<button ng-click="show = true">Click</button>
<div ng-show="show">
<input type="text" ng-model="value"/>
<div>{{value}}</div>
</div>
</div>
You should use $compile service to link scope and your template together:
angular.module('myApp', [])
.controller('MyCtrl', ['$scope', '$compile', '$document' , function MyCtrl($scope, $compile, $document) {
var ctrl = this;
var inputTemplate = '<div><span ng-bind="$ctrl.testModel"></span>--<span>{{$ctrl.testModel}}</span><input type="text" name="testModel"/></div>';
ctrl.addControllDynamically = addControllDynamically;
var id = 0;
function addControllDynamically() {
var name = "testModel_" + id;
var cloned = angular.element(inputTemplate.replace(/testModel/g, name)).clone();
cloned.find('input').attr("ng-model", "$ctrl." + name); //add ng-model attribute
$document.find('[ng-app]').append($compile(cloned)($scope)); //compile and append
id++;
}
return ctrl;
}]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//code.angularjs.org/1.6.2/angular.js"></script>
<div ng-app="myApp">
<div ng-controller="MyCtrl as $ctrl">
<input type="button" value="Add control dynamically" ng-click="$ctrl.addControllDynamically()"/>
</div>
</div>
UPDATE: to add a new compiled template each time the button is clicked, we need to make a clone of the element.
UPDATE 2: The example above represents a dirty-way of manipulating the DOM from controller, which should be avoided. A better (angular-)way to solve the problem - is to create a directive with custom template and use it together with ng-repeat like this:
angular.module('myApp', [])
.controller('MyCtrl', ['$scope', function MyCtrl($scope) {
var ctrl = this;
ctrl.controls = [];
ctrl.addControllDynamically = addControllDynamically;
ctrl.removeControl = removeControl;
function addControllDynamically() {
//adding control to controls array
ctrl.controls.push({ type: 'text' });
}
function removeControl(i) {
//removing controls from array
ctrl.controls.splice(i, 1);
}
return ctrl;
}])
.directive('controlTemplate', [function () {
var controlTemplate = {
restrict: 'E',
scope: {
type: '<',
ngModel: '='
},
template: "<div>" +
"<div><span ng-bind='ngModel'></span><input type='type' ng-model='ngModel'/></div>" +
"</div>"
}
return controlTemplate;
}]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//code.angularjs.org/1.6.2/angular.js"></script>
<div ng-app="myApp">
<div ng-controller="MyCtrl as $ctrl">
<input type="button" value="Add control dynamically" ng-click="$ctrl.addControllDynamically()"/>
<div ng-repeat="control in $ctrl.controls">
<control-template type="control.type" ng-model="control.value"></control-template>
</div>
</div>
</div>
I have created a directive so that the columns in a bootstrap row are of same height.
Here is the code - http://jsbin.com/waxoboloqo/edit
But it is not working. Can you please fix it ?
Html code:
<h1>Height: {{ hei }}</h1>
<div class="row">
<div class="col-lg-6 col-1">
<h1 ng-repeat="x in y" match-height>{{x}}</h1>
</div>
<div class="col-lg-6 col-2">
</div>
</div>
CSS:
.col-lg-6 {
border: 1px solid;
min-height: 50px;
}
Js:
angular.module('myApp', [])
.controller('myController', function($scope){
$scope.y = [1,2,3];
$scope.hei = "initial"
})
.directive('matchHeight', function(){
return function(scope, element) {
if(scope.$last){
scope.hei = $(element).height();
$(element).closest(".row").find(
".col-2").height(scope.hei);
}
}
});
you can try this.
app.directive('getHeight',function () {
return {
restrict: 'AE',
link: function (scope, element, attrs) {
scope.$watch(function(){
scope.style = {
height:element[0].offsetHeight+'px',
// width:element[0].offsetWidth+'px'
};
});
}
};
});
<div class="col-lg-6 col-1" get-height>
<h1 ng-repeat="x in y">{{x}}</h1>
</div>
<div class="col-lg-6 col-2" ng-style="style">
</div>
I am trying to get angular bootstrap datetimepicker input value using a custom directive like shown below. I am able to get the value in directive. How can i access this directive scope value in angular controller.
HTML
<div class='input-group date' id='datetimepickerId' datetimez ng-model="dueDate" >
<input type='text' class="form-control" />
</div>
Controller
App.directive('datetimez', function(){
return {
require: '?ngModel',
restrict: 'A',
link: function(scope, element, attrs, ngModel){
if(!ngModel) return;
ngModel.$render = function(){
element.find('#datetimepickerId').val( ngModel.$viewValue || '' );
};
element.datetimepicker({
format : 'YYYY-MM-DD HH:mm:ss'
});
element.on('dp.change', function(){
scope.$apply(read);
});
read();
function read() {
var value = element.find('#datetimepickerId').val();
ngModel.$setViewValue(value);
console.log(scope.dueDate);
}
}
};
});
App.controller('myController', ['$scope', function($scope) {
console.log($scope.dueDate);
}]);
Log inside the directive prints value successfully. But log inside controller does not.
Here you go.
I checked the documentation of the bootstrap datetimepicker and come to know there are two implementation.
One with a icon to click and show the datetimepicker
Another one just with a textbox without a icon
For the first one, you have to use the parent div to initiate the plugin and for the second option, you have to use the textbox to initiate the plugin
You have used the second option but used the parent div to initiate the plugin with a directive.
Also, div elements won't support the ngModel, hence directive should be used with the input element.
I have extended your directive to handle both scenarios and also the date format and other options can be passed from the controller.
You can give a try with the below working snippet.
var App = angular.module('App', []);
App.directive('datetimez', function(){
return {
require: '?ngModel',
restrict: 'A',
link: function(scope, element, attrs, ngModel){
if(!ngModel) return;
ngModel.$render = function(){
element.val( ngModel.$viewValue || '' );
};
function read() {
var value = element.val();
ngModel.$setViewValue(value);
//console.log(scope.dueDate);
}
var options = scope.$eval(attrs.datetimez) || {};
if(element.next().is('.input-group-addon')) {
var parentElm = $(element).parent();
parentElm.datetimepicker(options);
parentElm.on('dp.change', function(){
scope.$apply(read);
});
} else {
element.datetimepicker(options);
element.on('dp.change', function(){
scope.$apply(read);
});
}
read();
}
};
});
App.controller('myController', ['$scope', function($scope) {
$scope.datePickerOptions = {
format : 'YYYY-MM-DD HH:mm:ss'
};
$scope.$watch('dueDate1', function(){
console.log($scope.dueDate1);
});
$scope.$watch('dueDate2', function(){
console.log($scope.dueDate2);
});
}]);
angular.bootstrap(document, ['App']);
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.43/css/bootstrap-datetimepicker.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.16.0/moment.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.43/js/bootstrap-datetimepicker.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div class="container" ng-controller="myController">
<div class="row">
<div class='col-md-6'>
<div class="form-group">
<div class='input-group date' id='datetimepicker1'>
<input type='text' class="form-control" datetimez="datePickerOptions" ng-model="dueDate1" />
</div>
</div>
</div>
</div>
<div class="row">
<div class='col-md-6'>
<div class="form-group">
<div class='input-group date' id='datetimepicker1'>
<input type='text' class="form-control" datetimez="datePickerOptions" ng-model="dueDate2" />
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
</div>
</div>
</div>
</div>
I am trying to access the class of button which is placed next to paragraph. As soon as the focus gets on paragraph the class of button should change. Please see HTML the code below :
<div>
<span id="key" class="col-lg-2">email : </span>
<span ng-focus="focused($event)" id="value" contenteditable="true">abcd#abc.com</span>
<input type="submit" name="update" value="update"
class="update-hide" data-ng-click="updateValue($event)">
</div>
The angular code for controller is :
var TestParseController = function($scope, $window, $http, $routeParams, $sce,
$compile) {
$scope.focused = function(focusedValue) {
var par = focusedValue.target.parentNode;
var nodes = par.childNodes;
nodes[2].className="update-regular";
}
}
How could this be done in angular way? I know its something like $$nextSibling , but accessing the class name is problamatic. I have googled a lot and found nothing. Please help!!!
Please suggest any dynamic way i can not hardcode any id for button also.
This can be like below:
angular.module("app",[])
.controller("MainCtrl", function($scope) {
$scope.focused = function(focusedValue) {
var par = focusedValue.target.parentNode;
angular.element(par.querySelector("input[type=submit]")).addClass("update-regular");
}
});
.update-regular {
background: red;
}
<!DOCTYPE html>
<html ng-app="app">
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.min.js"></script>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body ng-controller="MainCtrl">
<div>
<span id="key" class="col-lg-2">email : </span>
<span ng-focus="focused($event)" id="value" contenteditable="true">abcd#abc.com</span>
<input type="submit" name="update" value="update"
class="update-hide" data-ng-click="updateValue($event)">
</div>
</body>
</html>
But mostly DOM manipulation must be done via directives. Controller must act mostly like ViewModel. So if you could create a directive and add it to the contenteditable span tag.
angular.module("app", [])
.directive("focusAdjacentButton", function () {
return {
restrict: "AEC",
link: function (scope, element, attrs) {
element.on("focus", function () {
angular.element(element[0].parentNode.querySelector("input[type=submit]")).addClass("update-regular");
});
// if you want to remove the class on blur
element.on("blur", function () {
angular.element(element[0].parentNode.querySelector("input[type=submit]")).removeClass("update-regular");
});
}
}
});
In your HTML:
<span focus-adjacent-button id="value" contenteditable="true">abcd#abc.com</span>
I am trying to track button clicks a user performs on a page/view. I am trying to get the element idwhich was clicked.
Is there a way to do this without having to tie a function or directive to each element?
ng-controller and ng-click
HTML:
<body ng-controller="MyController" ng-click="go($event)">
<div id="box1">
<div id="box2">
<div id="box3"></div>
</div>
</div>
</body>
JS:
$scope.go = function(e) {
var clickedElement = e.target;
console.log(clickedElement);
console.log(clickedElement.id);
};
Demo: http://plnkr.co/edit/1O6pCVrvgu7Bl8b6TlPF?p=preview
Directive:
HTML:
<body my-directive>
<div id="box1">
<div id="box2">
<div id="box3"></div>
</div>
</div>
</body>
JS:
app.directive('myDirective', function () {
return {
link: function (scope, element, attrs) {
element.bind('click', function (e) {
var clickedElement = e.target;
console.log(clickedElement);
console.log(clickedElement.id);
});
}
}
});
Demo: http://plnkr.co/edit/eevnMFu2YBj3QqRraeZh?p=preview