isolate scope won't update model - angular 1.6 - angularjs

We are trying to use a jquery time entry component in angularjs. We have a directive for the time entry component. When I try to change the ngModel from directive based on DOM value the model is not reflected. Please see the controller, index.html, app.js below.
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<link rel="stylesheet" href="style.css" />
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="jquery.plugin.js"></script>
<script src="jquery.timeentry.js"></script>
<script data-require="angular.js#1.0.x" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js" data-semver="1.0.8"></script>
<script src="script.js"></script>
</head>
<body ng-controller="MainCtrl">
<p>Time {{orderPermitViews[0].permitDetails[0].effectiveTimeForDispaly}}!</p>
<div ng-repeat="permitDetail in orderPermitViews[0].permitDetails">
<input type="text" name="spinner" class="time-spinner"
time-spinner ng-model="permitDetail.effectiveTimeForDispaly" >
</div>
</body>
</html>
angular.module('plunker', [])
.directive('timeSpinner', function() {
return {
restrict: 'A',
scope: {timeModel: "=ngModel"},
link: function( scope, elem, attrs) {
$(elem).timeEntry({
spinnerImage: 'assets/img/spinnerUpDown.png',
spinnerSize: [15, 16, 0],
spinnerBigSize: [30, 32, 0],
spinnerIncDecOnly: true,
show24Hours: true
}).change(function () {
scope.timeModel = $(elem).timeEntry('getTime');
console.log("Time model:" + scope.timeModel);
});
scope.$watch('timeModel', function(newValue, oldValue) {
$(elem).timeEntry('setTime', newValue);
console.log("Set time:" + newValue);
});
}
}
})
.controller('MainCtrl', function($scope) {
var permitDetails = new Array();
$scope.orderPermitViews = new Array();
$scope.orderPermitViews[0] = {};
$scope.orderPermitViews[0].permitDetails = new Array();
$scope.orderPermitViews[0].permitDetails[0] = {};
$scope.orderPermitViews[0].permitDetails[0].effectiveTimeForDispaly = new Date();
});
When I change the text, I see the change function getting executed and update the model. However it is not reflected in the HTML {{orderPermitViews[0].permitDetails[0].effectiveTimeForDispaly}}. I need some help in figuring out what is going wrong here.

Related

Bitmask checkbox group in angular

Quite straightforward, but I am fairly new to angular, and I think I have bitwise-sick, so I am kinda stuck :
// Checkboxes control existence of value in an array
var app = angular.module('myApp', []);
app.controller('MainController', function($scope) {
$scope.bitMaskFromDB = 5;
$scope.fruits = [{value:1, label: 'apple'}, {value:2, label:'orange'}, {value:4, label:'pear'}, {value:8, label:'naartjie'}];
});
app.directive('bitMask', function() {
return {
scope: {
bitMask: '=',
value: '#'
},
link: function(scope, elem, attrs ) {
var handler = function(setup) {
if (setup){
var checked = scope.bitMask&scope.value;
elem.prop('checked', checked);
}else{
var checked = elem.prop('checked');
if (!scope.bitMask&scope.value)
scope.bitMask |= scope.value
// elem.prop('checked', !checked);
scope.bitMask ^= scope.value
}
console.log ('bit = '+ scope.bitMask)
// console.log ('value = '+ scope.value)
// console.log ('checked ='+ checked)
};
var setupHandler = handler.bind(null, true);
var changeHandler = handler.bind(null, false);
elem.on('change', function() {
scope.$apply(changeHandler);
});
scope.$watch('bitMask', setupHandler, true);
}
};
});
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="utf-8">
<title>Custom Plunker</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular.min.js"></script>
<link rel="stylesheet" href="style.css">
<script>
document.write('<base href="' + document.location + '" />');
</script>
<script src="app.js"></script>
</head>
<body ng-app="myApp" ng-controller='MainController'>
Bitmask checkboxes <br>
<span ng-repeat="fruit in fruits">
<input type='checkbox' value="{{fruit.value}}" bit-mask='bitMaskFromDB' > {{fruit.label}}<br />
</span>
<div>Current value of bitmask: {{bitMaskFromDB }}</div>
</body>
</html>
I failed to
1/ change the bit mask value correctly to checkbox values and
2/ show/bind value back to controller
http://plnkr.co/edit/3M8KNyOxMBgPwj9jf01q
You are very close my friend.
Here is the fix for you. Well, I don't really remember what they said about that. But there are weird behavior binding primitive to scope
updated your plkr
// Checkboxes control existence of value in an array
var app = angular.module('myApp', []);
app.controller('MainController', function($scope) {
$scope.IforgetHowTheyExplainThis = {bitMaskFromDB:5};
$scope.fruits = [{value:1, label: 'apple'}, {value:2, label:'orange'}, {value:4, label:'pear'}, {value:8, label:'naartjie'}];
});
app.directive('bitMask', function() {
return {
scope: {
bitMask: '=',
value: '#'
},
link: function(scope, elem, attrs ) {
var handler = function(setup) {
if (setup){
console.log ('value1 = '+ scope.value)
var checked = scope.bitMask&scope.value;
elem.prop('checked', checked);
}else{
console.log ('value2 = '+ scope.value)
var checked = elem.prop('checked');
if (!scope.bitMask&scope.value)
scope.bitMask |= scope.value
else
scope.bitMask ^= scope.value
}
console.log ('bit = '+ scope.bitMask)
// console.log ('value = '+ scope.value)
// console.log ('checked ='+ checked)
};
var setupHandler = handler.bind(null, true);
var changeHandler = handler.bind(null, false);
elem.on('change', function() {
scope.$apply(changeHandler);
});
scope.$watch('bitMask', setupHandler, true);
}
};
});
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="utf-8">
<title>Custom Plunker</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular.min.js"></script>
<link rel="stylesheet" href="style.css">
<script>
document.write('<base href="' + document.location + '" />');
</script>
<script src="app.js"></script>
</head>
<body ng-app="myApp" ng-controller='MainController'>
Bitmask checkboxes <br>
<span ng-repeat="fruit in fruits">
<input type='checkbox' value="{{fruit.value}}" bit-mask='IforgetHowTheyExplainThis.bitMaskFromDB' > {{fruit.label}}<br />
</span>
<div>Current value of bitmask: {{IforgetHowTheyExplainThis.bitMaskFromDB }}</div>
</body>
</html>

why is $watch value parameter sometimes a string value and sometimes a function?

I've seen cases where the first parameter of a $watch is simply a string rather than a function. When do you use a function and when do you use the string?
In this plunker, I did this both ways. The $watch in the controller uses a function, while the $watch in the directive uses a string. They both work, but I just don't understand the rules as to why it a function in one case and then a string in the other case. Can anyone please explain this to me?
http://plnkr.co/edit/hSdQcRnvYn16ZeeJyPaM?p=preview
app = angular.module('app', []);
app.controller('mainCtrl', MainCtrl);
function MainCtrl($scope) {
$scope.myColor1 = 'blue';
$scope.myColor2 = 'blue';
$scope.$watch(function(scope) {
return scope.myColor1;
},
function(newValue, oldValue) {
$scope.myStyle = 'color:' + $scope.myColor1
}
);
}
app.directive('fontColor', FontColor);
function FontColor() {
return {
restrict: 'A',
link: function(scope, el, attrs) {
scope.$watch(attrs['fontColor'], function(newVal) {
console.log(newVal)
el.css('color', newVal)
})
}
}
}
HTML:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css" />
<link data-require="bootstrap-css#*" data-semver="3.3.1" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" />
<script data-require="jquery#*" data-semver="2.1.4" src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
<script data-require="angular.js#1.4.5" data-semver="1.4.5" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
<script src="script.js"></script>
</head>
<body ng-app="app" ng-controller="mainCtrl" class="container" style="padding-top:30px">
<div style="{{myStyle}}">color1</div>
<input type="text" ng-model='myColor1'>
<br><br>
<div font-color="myColor2">color2</div>
<input type="text" ng-model="myColor2">
</body>
</html>
That's just how $watch is defined in Angular. You can see the documentation for it here: $watch doc
It states that the first argument to $watch can be one of either:
string: evaluated as expression, or
function(scope): called with current scope as parameter

AngularJS : Adding attribute to directive element inside ng-repeat not working

I have a directive that works fine when used in isolation, but when it is used inside an ng-repeat it quits working. I know that ng-repeat creates it's own isolate scope, but that shouldn't matter since I'm not trying to do anything outside of the isolate scope of my directive. I've created a plunker to demonstrate the problem which you can see here: http://plnkr.co/edit/Y4ADmznnDCZvuxJrcZQ0?p=preview.
In the compile function of the directive I am adding an ng-click attribute to the element. Notice that the "This works" link (which is not in an ng-repeat) works fine but the other links (which are inside ng-repeat) do not work.
Here is the directive from the plunker:
var app = angular.module('plunker', []);
app.controller("AppCtrl", function($scope) {
$scope.users = [{
name: 'John',
id: 1
}, {
name: 'anonymous'
}];
});
app.directive("myDir", function($compile) {
return {
controller: 'directiveController',
compile: function(el) {
el.removeAttr('my-dir');
el.attr('ng-click', 'fxn()');
var fn = $compile(el);
return function(scope){
fn(scope);
};
}
};
})
.controller("directiveController", function($scope) {
$scope.fxn = function() {
alert('It works');
};
});
And here is the html:
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.2.x" src="http://code.angularjs.org/1.2.12/angular.js" data-semver="1.2.12"></script>
<script src="app.js"></script>
</head>
<body>
<div>
<a my-dir>This works</a>
<a my-dir ng-repeat="id in [1,2]"><br>This does not work</a>
</div>
</div>
</body>
</html>
Try it with binding the event in the link function instead of adding another attribute that has to be compiled (DEMO):
app.directive("myDir", function($compile) {
return {
controller: 'directiveController',
compile: function(el) {
el.removeAttr('my-dir');
var fn = $compile(el);
return function(scope, el){
el.bind('click', scope.fxn);
fn(scope);
};
}
};
})

How can I set the value of an id in the template part of a directive?

I am trying this:
http://plnkr.co/edit/IzhScWwcy6owjsPKm2Fs?p=preview
<!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.0.2/angular.js"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
xx<div admin-select
admin-id="examType"></div>xx
</body>
</html>
and
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
});
app.directive("adminSelect", function () {
return {
restrict: 'A',
require: 'ngModel',
scope: {
adminId: '=adminId'
},
template: '<div id="{{adminId}}"></div>'
};
});
This is not working and I cannot see why. Can someone give me some advice and help me to set the id of the <div> that's part of the template.
You have to put the value of the admin-id attribute under apostrophe because you want to set the value. Example
<div admin-select admin-id="'examType'"></div>
Otherwise you set the scope variable in the controller and pass this variable to the directive:
app.controller('MainCtrl', function($scope) {
$scope.myId = 'examType'
});
<div admin-select admin-id="myId"></div>
Example
template: '<div id="{{$parent.adminId}}"></div>'
Angular's docs has this "the root of the template always gets a new scope.", maybe that's why.
Upddated
this answer is not working... =)

Watch not working when HTML loaded from Directive in AngularJS

I am loading a partial in Angular dependant on the route of the URL.
When I load the partial it loads, and responds to the Controllers functions. However I have a directive which has a watcher. This does not work when I use the
It works fine when I load the HTML inside the main page. I have a Plunker of this here
http://plnkr.co/edit/DK33pIrp0HyhUOjwm5X2?p=preview
Essentially clicking "hello" should change the $scope.origin and the watcher should then fire its event. It does not.
My HTML:
<!DOCTYPE html>
<html ng-app="App">
<head lang="en">
<meta charset="utf-8">
<title>Custom Plunker</title>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular.min.js"></script>
<link rel="stylesheet" href="style.css">
<script>
document.write('<base href="' + document.location + '" />');
</script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/coffee-script/1.1.2/coffee-script.min.js"></script>
<script src="app.js"></script>
<script src="directive.js"></script>
</head>
<body ng-controller="MapCtrl">
<ng-view></ng-view>
</body>
</html>
app.js
var app;
app = angular.module("App", []);
app.config(function($routeProvider) {
return $routeProvider.when("/", {
templateUrl: "home.html",
controller: MapCtrl
});
});
this.MapCtrl = function($scope) {
return $scope.clicked = function() {
console.log("clicked");
$scope.origin = Math.floor(Math.random() * 11);
return console.log($scope.origin);
};
};
directive.js
(function(angular) {
var app;
app = angular.module("App");
return app.directive("leaflet", function() {
return {
restrict: "E",
replace: true,
transclude: true,
template: "<section id='map' class='map'></section>",
scope: {
origin: "=origin"
},
controller: function($scope, $attrs) {
return $scope.$watch("origin", (function(newValue, oldValue) {
return alert("its changed");
}), true);
}
};
});
})(angular);
home.html
<button ng-click="clicked()">hello</button>
how can I get this working?
edit: I have just made this pure JS and not coffeescript.
Thanks so all who helped me find the issue.
This can be done by setting the
<button ng-click="clicked()">hello</button>
to
<button ng-click="$parent.clicked()">hello</button>
This is because the ng-view will be a child. This simple fix is now working.

Resources