Can't update $scope value in directive - javascript

This directive fires when ng-repeat finishes using scope.$last:
simpleSearchApp.directive('afterResults', function($document) {
return function(scope, element, attrs) {
if (scope.$last){
scope.windowHeight = $document[0].body.clientHeight;
}
};
});
I'm trying to update $scope.windowHeight with a new value but I can't access $scope inside the directive.
My ng-repeat HTML with directive:
<div ng-show="items" class="ng-cloak" ng-repeat="item in items" after-results>
{{item}}
</div>

Honestly saying I have also not understand why it's not updating. But the the alternate approach to update variable in controller is to define a function wich update the variable and call that function in controller from directive. Please take a look at the following example it might help you.
angular.module('app',[]).controller('MyController',['$scope',function($scope){
$scope.windowHeight = 0;
$scope.updateWindowHeight = function(height){
$scope.windowHeight = height;
}
}])
.directive('afterResults', function($document) {
return function(scope, element, attrs) {
if (scope.$last){
scope.windowHeight = $document[0].body.clientHeight;
scope.updateWindowHeight( scope.windowHeight);//calling function in controller
}
};
});
<!DOCTYPE html>
<html ng-app="app">
<head>
<script data-require="angular.js#1.4.1" data-semver="1.4.1" src="https://code.angularjs.org/1.4.1/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller="MyController">
<div class="ng-cloak" ng-repeat="item in [1,2,3,4,5]" after-results="updateWindowHeight()">
{{item}}
</div>
<hr/>{{ "$scope.windowHeight ="+windowHeight}}
</body>
</html>

Related

How to use custom directive on Input fields in Angular 1.x?

I'm trying to modify the input element using a custom AngularJS directive. Basically I want to replace any <input type="country"> fields with a country drop-down.
But the directive doesn't seem to work with input fields. If I change it to any other tag, it works?
Here is the code:
angular.module('plunker', [])
.controller('MainCtrl', function ($scope) {
$scope.name = 'World';
});
angular.module('plunker')
.directive('input', function() {
return {
restrict: 'E',
scope: {ngModel: '=?'},
link: function(scope, elem, attr) {
if(attr.type === 'country') {
elem.html('html code for select');
alert(elem);
}
}
};
});
<!doctype html>
<html ng-app="plunker" >
<head>
<meta charset="utf-8">
<title>AngularJS Plunker</title>
<link rel="stylesheet" href="style.css">
<script>document.write("<base href=\"" + document.location + "\" />");</script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
Name: <input type="country" ng-model="name"/> <br/>
</body>
</html>
Can someone please explain and suggest a workaround?
P.S. I've also tried doing this in the directive, but it doesn't work either!
replace: true,
template:'<div>hello</div>'
P.S. I know I can use a ng-country or some other custom tag but I want to change input tag only because I want learn why this is happening or possibly find out what I'm doing wrong?
Latest Update:
Your code is just setting the html on the element, instead of replacing it. You would want to use replaceWith instead like this:
var app = angular.module("TestApp",[]);
app.controller("TestController", function($scope){
$scope.message = "Input Directive Test"
});
app.directive("input", function() {
return {
restrict: "E",
link: function(scope, elem, attr) {
if(attr.type === "country") {
var select = angular.element("<select><option>USA</option></select>");
elem.replaceWith(select);
}
}
}
});
And here's the JSBin: https://jsbin.com/juxici/4/edit?html,js,output
Initial Version of my answer:
Here's an example that works without any issues when 'replace' and 'template' are used. I'm not checking for type and such, but you could do that in the linker code.
JSBin: https://jsbin.com/juxici/2/edit?html,js,output
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
</head>
<body ng-app="TestApp">
<div ng-controller="TestController">
<h2>{{message}}</h2>
<input type="country" ng-model="name"/>
</div>
</body>
</html>
Javascript:
var app = angular.module("TestApp",[]);
app.controller("TestController", function($scope){
$scope.message = "Input Directive Test"
});
app.directive("input", function() {
return {
restrict: "E",
replace: true,
template:"<select><option>USA</option></select>"
}
});

interpolating an attribute value in an Angular template causes a parse error

I am getting the error: angular.js:10627 Error: [$parse:syntax]
when interpolating a value in the template, only when it's in the attribute of an element.
template field_message.html:
<input type="number" ng-model="{{ model }}">
<div>{{ model }}</div>
directive:
myApp.directive('ivInput', function(){
return {
restrict: 'EA',
templateUrl: "field_message.html",
scope: {
model: '#ngModel'
}
};
});
view html:
<div iv-input="flatK" ng-model="modelname"></div>
In the template, the first instance of {{ model }} causes a parse error. If I remove this, the other instance correctly renders out the model name. Is there a way to get the model name into the value for ng-model on the input element?
Working absolutely fine.
<!DOCTYPE html>
<html lang="en" ng-app="app">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.js"></script>
<meta charset="UTF-8">
</head>
<body ng-controller="ctrl">
<div iv-input="flatK" ng-model="modelname"></div>
<span>{{modelname}}</span>
<script>
var app = angular.module('app', []);
app.directive('ivInput', function(){
return {
restrict: 'EA',
template: "<input type='number' ng-model='ngModel'>"+
"<div>{{ model }}</div>",
scope: {
ngModel:'='
}
};
});
app.controller('ctrl',function($scope){
$scope.modelname=23;
} )
</script>
</body>
</html>

Unable to inject directive as dependency in AngularJS

I am learning to create directives and made them available via dependency add, but somehow it is not working, let me know what I am doing wrong.
Plnkr - http://plnkr.co/edit/Mk4h7XvSN2YA26JZZ9Ua?p=preview
index.html
<!DOCTYPE html>
<html lang="en" ng-app="myApp">
<head>
<script src="https://code.angularjs.org/1.4.7/angular.js"></script>
<script type="text/javascript" src="firstDirective.js"></script>
<script type="text/javascript" src="script.js"></script>
</head>
<body ng-controller="mainCtrl as vm">
<div class="container">
<simple-directive></simple-directive>
</div>
</body>
</html>
firstDirective.js
angular
.module('firstdirective')
.directive('simpleDirective', function(){
return {
scope: true, // inherit child scope from parent
restrict: 'E',
replace: true,
template: '<h2>My first directive from dependency</h2>'
};
});
script.js
var myApp = angular.module('myApp', ['firstdirective']);
myApp.controller('mainCtrl', function(){
var vm = this;
})
To create a new module you need to pass an array of dependencies as the second argument:
angular.module('firstdirective', [])
Otherwise you are trying to retrieve the module.

how to create a directive with select and button

I have created a directive which should be able to call a function in a controller and use a variable in controller and directive.
I can not figure out how to call the callback.
I can not figure out to enable two way data binding on my directive scope variable.
Here is the plnk: http://plnkr.co/edit/T1bMYUnkPeZmHHd05SCI?p=preview
html
<!DOCTYPE html>
<html data-ng-app="App">
<head>
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body data-ng-controller="BodyCtrl">
<h1>{{title}}</h1>
<div class="container">
<div class="dateselector" data-ng-select="select" data-ng-refresh="refresh()"></div>
</div>
<script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.13/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.13/angular-route.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
<script src="script.js"></script>
</body>
</html>
html template
<div class="row">
<div class="col-md-3 col-sm-3">
<select class="form-control" ng-model="select" ng-options="p for p in possibilities"></select>
</div>
<div class="col-md-3 col-sm-3">
<button type="button" class="btn btn-default">Refresh</button>
</div>
</div>
javascript
var app = angular.module('App', ['ui.select']);
app.controller('BodyCtrl', ['$scope', function($scope) {
$scope.title = 'Select Directive';
$scope.select = 1;
$scope.refresh = function() {
alert("Refresh in Controller! " + $scope.select);
};
}]);
// Module
angular.module('ui.select', [])
.directive('dateselector', ['$parse', function($parse) {
var link = function ($scope, $element, $attributes) {
$scope.possibilities = [1,2,3,4,5,6];
$element.find('button').bind('click', function() {
alert('Refresh in directive!');
// How to call callback?
$scope.refresh;
});
};
return {
restrict: 'EC',
replace: true,
templateUrl: 'template.html',
scope: {
select: "=",
refresh: "&"
},
link: link
};
}]);
The basic problem is that your directive expects to see and attribute of the form some-name or data-some-name, but you specify one like this: data-ng-some-name.
Additionally, the recommended way to bind a callback to a button's click event is using ngClick.
<!-- In the VIEW -->
<div class="dateselector" data-select="select" data-refresh="refresh()"></div>
<!-- In the TEMPLATE -->
<button ... ng-click="refresh()">Refresh</button>
See, also, this modified demo.

Change focus to next input using ui-keypress in AngularJS

I use ui-keypress directive in input fields to apply the function newline() that creates a new input field under the current(focused) one. It works ok, but I want to update this function so the focus jumps down to the newly created field.
Here is my index.html:
<!doctype html>
<html ng-app="myApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0-rc.2/angular.min.js">
</script>
<script src="script.js"></script>
<script src="keypress.js"></script>
</head>
<body ng-controller="TextCtrl">
<div ng-repeat="task in tasks track by $index">
<input type="text" class="form-control" ng-model="task.text" ui-keypress="{13:'newline($index+1)'}" >
</div>
</body>
</html>
And this is script.js:
var myAppModule = angular.module('myApp', ['ui.keypress']);
myAppModule.controller('TextCtrl',function($scope){
var emptytask = '';
var tasks=[{text:'chart'}];
$scope.tasks = tasks;
$scope.newline = function(index){
$scope.tasks.splice(index,0,{text:emptytask});
};
});
Can you try something like this in directive
.directive('focusOnLoad', function () {
return {
restrict: 'E',
link: function (scope, element, attrs) {
$timeout(function() {
element.find('input').focus()
},0);
}
}
}
On HTML do
<div ng-repeat="task in tasks track by $index" focus-on-load>
In controller just add the new task.

Categories