AngularJS how to bind the ng-model on $watch - angularjs

I'm building an app using ionic framework and in my search module I'm using a library called ion-autocomplete https://github.com/guylabs/ion-autocomplete trying to bind the ng-model to my scope but I can't get it to bind.
Controller:
$scope.model = "";
$scope.callbackMethod = function (query) {
//scope.model doesn't bind
return PostService.SearchUser($scope.model, $localStorage.CurrentUser.auth_token, -1, -1)
.success(function (data) {
console.log(data);
})
.error(function(error) {
});
};
View:
//this derective is an input field
<ion-autocomplete ng-model="model" items-method="callbackMethod(query)" placeholder="Enter something"/>
Template:
var template = '<input type="search" class="ion-autocomplete-search" ng-model="searchQuery" placeholder="{{placeholder}}"/>'
Directive:
.directive('ionAutocomplete', function () {
return {
require: '?ngModel',
restrict: 'E',
template: '<input ion-autocomplete type="text" readonly="readonly" class="ion-autocomplete" autocomplete="off" />',
replace: true
}
});

Related

Angular assign value from directive to object

I have this custom directive:
var geo = angular.module('Geo', ['Gealocation']);
function SearchForm($scope){
$scope.location = '';
$scope.doSearch = function(){
if($scope.location === ''){
alert('Directive did not update the location property in parent controller.');
} else {
alert('Yay. Location: ' + $scope.location);
}
};
}
/* Directives */
angular.module('Gealocation', []).
directive('googlePlaces', function(){
return {
restrict:'E',
replace:true,
// transclude:true,
scope: {location:'='},
template: '<input id="google_places_ac" name="google_places_ac" type="text" class="form-control"/>',
link: function($scope, elm, attrs){
var autocomplete = new google.maps.places.Autocomplete($("#google_places_ac")[0], {});
google.maps.event.addListener(autocomplete, 'place_changed', function() {
var place = autocomplete.getPlace();
$scope.location = [place.geometry.location.lat(), place.geometry.location.lng()];
$scope.$apply();
});
}
}
});
geo.controller('SearchForm', SearchForm);
And in index.html i have few input and custom directive:
<input type="text" class="form-control" ng-model="meeting.topic"></input>
<input type="text" class="form-control" ng-model="meeting.when"></input>
<input type="text" class="form-control" ng-model="meeting.level"></input>
<input type="text" class="form-control" ng-model="meeting.describe"></input>
<google-places location=location></google-places>
<button ng-click="doSearch()" class="btn btn-large btn-primary">Search!</button>
and to display value(location with lat and lng) from directive i can do that by:
{{location}}
But how can i assign this location to something like that :
meeting.location
becouse i need to pass later object meeting
I solved this by:
In controller:
$scope.meeting = {
location: ''
};
In view:
{{meeting.location = location}}

How to access ng-model value in directive?

I created a directive for google map auto-complete. everything is working fine, but the problem is when I need to access the value of input and re-set it. it doesn't work. Here is code:
<div controller='mainCtr'>
<span click='reset(destination)'>Reset</span>
<div class='floatleft' style='width:30%;margin-right:40px;'>
<smart-Googlemaps locationgoogle='destination.From'></smart-Googlemaps>
<label>From</label>
</div>
</div>
In the directive:
angular.module('ecom').directive('smartGooglemaps', function() {
return {
restrict:'E',
replace:false,
// transclude:true,
scope: {
locationgoogle: '='
},
templateUrl: 'components/directives/autocomplete/googlemap-search.html',
link: function($scope, elm, attrs){
var autocomplete = new google.maps.places.Autocomplete($(elm).find("#google_places_ac")[0], {});
google.maps.event.addListener(autocomplete, 'place_changed', function() {
var place = autocomplete.getPlace();
// $scope.location = place.geometry.location.lat() + ',' + place.geometry.location.lng();
// console.log(place);
$scope.locationgoogle = {};
$scope.locationgoogle.formatted_address = place.formatted_address;
$scope.locationgoogle.loglat = place.geometry.location;
$scope.locationgoogle.locationText = $scope.locationText;
$scope.$apply();
});
}
}
})
Here is html for directive:
<input id="google_places_ac" placeholder="Please enter a location" name="google_places_ac" type="text" class="input-block-level" ng-model='locationText'/>
The directive works fine, I create a isolated scope(locationgoogle) to pass the information I need to parent controller(mainCtr), now in the mainCtr I have a function calld reset(), after I click this,I need to clean up the input make it empty. How Can I do it?
One way to access the value of the model in your directive from a parent controller is to put that on the isolate scope too and use the two-way binding flag = like you've done with the locationgoogle property. Try this:
DEMO
html
<body ng-controller="MainCtrl">
<button ng-click="reset()">Reset</button>
<smart-googlemaps location-text="locationText"></smart-googlemaps>
</body>
js
app.controller('MainCtrl', function($scope) {
// need to define model in parent and pass to directive
$scope.locationText = {
value: ''
};
$scope.reset = function(){
$scope.locationText.value = '';
}
});
app.directive('smartGooglemaps', function() {
return {
restrict:'E',
replace:false,
// transclude:true,
scope: {
locationgoogle: '=',
locationText: '='
},
// ng-model="locationText.value"
template: '<input id="google_places_ac" placeholder="Please enter a location" name="google_places_ac" type="text" class="input-block-level" ng-model="locationText.value"/>',
link: function($scope, elm, attrs){
// implement directive googlemaps logic, set text value etc.
$scope.locationText.value = 'foo';
}
}
})

When I change the value of an input clicking on a button $bindTo doesn't work firebase

So I'm beginner to angularjs and firebase and I'm trying to develop an app which adds values(numerical) on an input. So far I have this:
app.js:
var app = angular.module("app", ['firebase']);
app.directive('addOne', function() {
return {
link: function(scope,element) {
element.bind('click', function() {
console.log(element.parent().find('input'))
element.parent().find('input')[1].value++;
});
}
}
});
and my view:
<section class="form-group">
<label for="">$</label> <input type="button" value="+" add-one>
<input ng-model="user.level" type="text" class="form-control" />
</section>
and my controller:
app.controller('mController', ['$scope', 'User',
function($scope, backHome, User, adicionar){
$scope.user = User(1);
User(1).$bindTo($scope, "user");
}
]);
the thing is that after I click the button with the directive add-one the value of the input changes but the $bindTo is not working...
So why does the bindTo doesn't work when I make a change directly in the DOM?
AngularJS doesn't care what the value of an input is set to, it only cares about what's in the ng-model. Try this...
app.directive('addOne', function() {
return {
link: function(scope,element) {
element.on('click', function() {
scope.$apply(function(){
scope.user.level++
});
});
}
}
});
As pointed out by #PankajParkar, you also need to use scope.$apply when you want to update a binding from event.
angular.module('demo', [])
.controller('DemoController', function($scope){
$scope.user={level: 1};
})
.directive('addOne', function() {
return {
link: function(scope, element, attrs) {
element.on('click', function() {
scope.$apply(scope.user.level++);
});
}
}
})
.directive('unaryInput', function(){
return {
restrict: 'EA',
scope: {
model: "=",
txt: '#buttonText'
},
template: '<input type="text" ng-model="model" /><button>{{txt}}</button>',
link: function(scope, element, attrs) {
if(angular.isDefined(attrs.initialVal)) {
scope.model = attrs.initialVal;
}
element.on('click', function() {
if (attrs.direction === 'decrement') {
scope.$apply(scope.model--);
} else {
scope.$apply(scope.model++);
}
});
}
};
});
<script src="https://code.angularjs.org/1.3.15/angular.min.js"></script>
<div ng-app="demo" ng-controller="DemoController">
<input type="text" ng-model="user.level">
<input type="button" value="+" add-one>
<hr>
<unary-input button-text="Add one" model="user.level" direction="increment"></unary-input>
<unary-input button-text="-" model="user.level" direction="decrement"></unary-input>
<hr>
<unary-input button-text="-" model="user.val" direction="decrement" initial-val="10"></unary-input>
</div>
In AngularJS, you want to change the view by changing the model that it's based on, versus doing it imperatively like you might with a traditional jQuery approach for example (traversing the DOM and incrementing the value).
UPDATE
Okay, so here's a nice reusable version of the (please check the snippet to see it in action).
The template includes both the button and the input. It accepts 4 values that you set as attributes:
button-text: The text you want to show on the button.
model: The model value for the input.
initial-val: The initial value for the input if you don't want to initialize on your controller.
direction: Whether to increment or decrement the values. This one currently accepts a string "decrement" to subtract. If you have no direction set or any other value set in the attribute, it will increment.
So, you would use it like this:
<unary-input button-text="Subtract One" model="user.val" direction="decrement" initial-val="10"></unary-input>
And the directive itself looks like this:
.directive('unaryInput', function(){
return {
restrict: 'EA',
scope: {
model: "=",
txt: '#buttonText'
},
template: '<input type="text" ng-model="model" /><button>{{txt}}</button>',
link: function(scope, element, attrs) {
if(angular.isDefined(attrs.initialVal)) {
scope.model = attrs.initialVal;
}
element.on('click', function() {
if (attrs.direction === 'decrement') {
scope.$apply(scope.model--);
} else {
scope.$apply(scope.model++);
}
});
}
};
});
Browsing around I could find a solution doing the way you said in the comments (two buttons one incrementing and another decrementing) thanks a lot for the help! and here's the final version.
app.directive('unaryInput', function(){
return {
restrict: 'EA',
scope: {
model: "="
},
template: '<input type="text" ng-model="model" /><button ng-click="decrement()">-</button><button ng-click="increment()">+</button>',
link: function(scope, element) {
scope.increment = function() {
scope.model++;
}
scope.decrement = function() {
scope.model--;
}
}
};
});

Angularjs directive with bi-directional binding not working

I'm trying to write a simple directive that allows the user to edit a certain variable, but when i try to update the parent variable it doesn't work.
this is my html:
<p class="scene-field-name editable-name" editable="foo"> {{foo}} </p>
and the directive:
myApp.directive('editable', function ($window, $compile) {
return {
restrict: "A",
template: '<div class="editable-value" ng-hide="editorOn">{{value}} <a class="edit-a" ng-click="editorOn = true">edit</a></div>' +
'<div class="editable-editor" ng-show="editorOn">' +
'<input type="text" value="{{tmpValue}}" />' +
'<a ng-click="setValue()">OK</a>' +
'</div>',
scope: {
value: "=editable"
},
controller: function($scope) {
$scope.tmpValue = $scope.value;
$scope.editorOn = false;
$scope.setValue = function () {
$scope.value = $scope.tmpValue;
$scope.editorOn = false;
}
}
};
here it is in jsfiddle:
http://jsfiddle.net/4srx2z0c/2/
you can see that when clicking OK it doesn't save the value back in the parent scope...
You don't bind the input to tmpValue.
Instead of <input type="text" value="{{tmpValue}}" /> you should have <input type="text" ng-model="tmpValue" />.

Cannot access attribute that is a directive inside another directive's template

My custom directive is "testapp". I would like to access the value of "file-model" in its template, which would contain the file object to be uploaded. Whatever I do am not able to get the value, its displaying "undefined". Please suggest ways to solve this problem.
app.directive('testapp', function ($compile) {
return {
restrict: 'E',
scope: {
text: '#',
filem: '=fileModel'
},
require:'fileModel',
replace:true,
template: '<div class="col-xs-4" style="padding-left:0px"><div class ="jumbotron" id="Section1"><input type="text" name="id" id="section{{incr}}" placeholder="Section Heading" class="form-control"><form id="addLIForm1"><div ng-repeat="i in range(fileIncr) track by $index"><input type="text" name="file{{incr}}{{$index+1}}" id="file{{incr}}{{$index+1}}" class="form-control" placeholder="File Name" style="width:50%" ><input type = "file" id="path{{incr}}{{$index+1}}" file-model = "file{{incr}}{{$index+1}}"></div></form><a id="addMore" ng-click="addfile()" href="#">Add More File</a><a id="addMoreSec1" ng-click="add()" class="pull-right" href="#" ng-show="showValue">Add More Section</a></div></div>',
controller: function ($scope, $element,$window) {
$scope.incr=$window.globalIncr;
$scope.fileIncr=$window.globalfileIncr;
$scope.showValue=$window.globalsectionValue;
$scope.add = function () {
$window.globalsectionValue=false;
$window.globalIncr+=1;
$window.globalfileIncr=1;
var el = $compile("<testapp></testapp>")($scope);
$element.parent().append(el);
//alert($window.globalfileIncr);
//alert($element.parent().parent());
};
$scope.range=function(n)
{
return new Array(n);
}
$scope.addfile=function(){
alert($scope.filem);
$scope.fileIncr+=1;
$window.counterObject[$scope.incr] = $scope.fileIncr;
};
}
};
});

Resources