Last active
March 29, 2018 14:27
-
-
Save mbret/a53127facc86b8aa0a9fabf98d149507 to your computer and use it in GitHub Desktop.
Angularjs one way binding
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<meta http-equiv="content-type" content="text/html; charset=UTF-8"> | |
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.js"></script> | |
<style type="text/css"> | |
</style> | |
<title>Angular: true one way binding</title> | |
</head> | |
<body> | |
<div ng-app="demo"> | |
<app></app> | |
</div> | |
<script type="text/javascript"> | |
class App { | |
static get declaration () { | |
return { | |
selector: 'app', | |
binding: {}, | |
template: App.template, | |
controller: App | |
}; | |
} | |
static get $inject () { | |
return ['owService']; | |
} | |
constructor ({onChange}) { | |
this.state = { | |
firstName: '' | |
}; | |
this.handleChange = onChange(field => { | |
const {$name, $modelValue, $error} = field; | |
this.state[$name] = $modelValue; | |
}); | |
this.handleSecondChange = onChange(field => { | |
this.state.firstName = field.$modelValue; | |
}); | |
} | |
static get template () { | |
return ` | |
<p>App.state.firstName: {{$ctrl.state.firstName}}</p> | |
<form name="form"> | |
<label>This input is bound to a dummy ngModel so it will never mutate your state. </label> | |
<input | |
required | |
type="text" | |
name="firstName" | |
ng-maxlength="3" | |
ng-model="dummy.firstName" | |
ow-model="$ctrl.state.firstName" | |
ng-change="$ctrl.handleChange(form.firstName)" | |
ng-model-options="{allowInvalid: true}" | |
/> | |
<p> | |
<label>This input is bound to $ctrl.state.firstName so it should update firstName</label> | |
<input | |
type="text" | |
name="dummy" | |
ng-model="dummy.foo" | |
ng-change="$ctrl.handleSecondChange(form.dummy)" | |
ng-model-options="{allowInvalid: true}" | |
/> | |
</p> | |
</form> | |
`; | |
} | |
} | |
const directive = () => ({ | |
restrict: 'A', | |
require: 'ngModel', | |
scope: { | |
owModel: '<', | |
ngModel: '=', | |
}, | |
link: (scope) => { | |
scope.$watch('owModel', (newVal) => { | |
// only apply change to ngModel if fModel has different | |
// value. This is an optimization | |
if (newVal !== scope.ngModel) { | |
scope.ngModel = newVal; | |
} | |
}); | |
} | |
}); | |
const owService = ['$timeout', ($timeout) => ({ | |
// quick fix because when using: ng-model-options="{allowInvalid: true}" | |
// the sync validation happens after ngChange is fired.. unlike default value. | |
// @see https://github.com/angular/angular.js/issues/14043 | |
onChange: fn => (...args) => $timeout(() => fn(...args)) | |
})]; | |
angular | |
.module('demo', []) | |
.component(App.declaration.selector, App.declaration) | |
.directive('owModel', directive) | |
.factory('owService', owService); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment