binding data from same object to same multiple directive - angularjs

Hello I am little confused about how can I bind the same directive with different data from the same object
(function () {
'use strict';
angular.module('app', [])
.controller('appController', appController)
.directive('userForm', userForm);
/**#Injectable*/
function appController($http) {
let vm = this;
vm.user = {
userName: 'Test User',
email: 'test#gmail.com',
number: '1456',
address: 'zyz',
state: 'abcd',
city: 'xyz'
};
}
function userForm() {
return {
restrict: 'E',
scope: {
data:'='
},
templateUrl: 'public/app/form.directive.html',
controller: 'appController',
link: function (scope, attr, element) {
}
}
}
})();
<legend>{{headerLabel}}</legend>
<div class="form-group">
<label class="col-sm-3 control-label" for="textinput">{{label1.label1}}</label>
<div class="col-sm-9">
<input type="text" ng-model="data.userName" class="form-control">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label" for="textinput">{{label2}}</label>
<div class="col-sm-9">
<input type="text" class="form-control" ng-model="email">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label" for="textinput">{{label3}}</label>
<div class="col-sm-9">
<input type="text" class="form-control" ng-model="number">
</div>
</div>
<!--Main Index -->
<user-form data="vm.user"></user-form>
<user-form data="vm.user"></user-form>
Here I have used same directive two times and I want to bind the first directive with personal info like username, email and second directive should bind with address info.Is it possible to do this?

I wonder why you would want to do that, using a directive for two different purposes. I suggest creating 2 different directives for it. If you still want it, you can have a logic inside link in the directive function to perform different logics. Its not very elegant, but what you asked for is not either(imho)
(function () {
'use strict';
angular.module('app', [])
.controller('appController', appController)
.directive('userForm', userForm);
/**#Injectable*/
function appController($http) {
let vm = this;
vm.user = {
userName: 'Test User',
email: 'test#gmail.com',
number: '1456',
address: 'zyz',
state: 'abcd',
city: 'xyz'
};
}
function userForm() {
return {
restrict: 'E',
scope: {
data:'=',
type:'#'
},
templateUrl: 'public/app/form.directive.html',
controller: 'appController',
link: function (scope, attr, element) {
switch(scope.type){
case 'name_info':
//logic for name based info
break;
case 'address_info':
//logic for address based info
break;
default:
}
}
}
}
})();
<legend>{{headerLabel}}</legend>
<div class="form-group">
<label class="col-sm-3 control-label" for="textinput">{{label1.label1}}</label>
<div class="col-sm-9">
<input type="text" ng-model="data.userName" class="form-control">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label" for="textinput">{{label2}}</label>
<div class="col-sm-9">
<input type="text" class="form-control" ng-model="email">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label" for="textinput">{{label3}}</label>
<div class="col-sm-9">
<input type="text" class="form-control" ng-model="number">
</div>
</div>
<user-form data="vm.user" type="name_info"></user-form>
<user-form data="vm.user" type="address_info"></user-form>

Related

My AngularJS 1.5 component called booking-info isn't populating the input fields in my form with booking data

I have a form inside a bookingEdit component and a bookingInfo component containing the form's input fields. The fields inside bookingInfo component aren't being populated with the booking data. How can I get these fields to be populated using my booking-info and booking-edit components?
booking-edit.template.html
<form name="$ctrl.form" ng-submit="$ctrl.updateBooking()">
<fieldset>
<legend>Edit Booking</legend>
<booking-info booking="$ctrl.booking"></booking-info>
<button class="btn btn-success" type="submit">Save</button>
</fieldset>
</form>
booking-edit.component.js
'use strict';
angular.
module('bookingEdit').
component('bookingEdit', {
templateUrl: 'booking-edit.template.html',
controller: ['BookingService','$location',
function (BookingService,$location) {
let self = this;
self.$routerOnActivate = function(next, previous) {
self.booking = BookingService.get({ id: next.params.id });
};
self.updateBooking = function () {
BookingService.update({ id: self.booking.bookingId }, self.booking)
.$promise
.then(
function () {
$location.path('/list');
},
function (error) {
}
);
};
}
]
});
booking-info.component.js
angular.module('app').
component('bookingInfo', {
templateUrl: 'booking-details.html',
bindings: {
booking:'<'
},
controller: function(){
let self = this;
}
});
booking-details.html
<div class="form-group">
<label for="contactName">Contact Name</label>
<input required type="text" class="form-control" ng-model="booking.contactName">
</div>
<div class="form-group">
<label for="contactNumber">Contact Number</label>
<input required type="tel" class="form-control" ng-model="booking.contactNumber">
</div>
You seem to forgot the $ctrl in booking-details.html
<div class="form-group">
<label for="contactName">Contact Name</label>
<input required type="text" class="form-control" ng-model="$ctrl.booking.contactName">
</div>
<div class="form-group">
<label for="contactNumber">Contact Number</label>
<input required type="tel" class="form-control" ng-model="$ctrl.booking.contactNumber">
</div>

AngularJs custom directive passing scope

I have $scope.loaded=false; in controller. Seems like directive doesn't pick up the scope, because ng-show="loaded" still shows DIV. But when I click button and controller changes $scope.sent to true, directive gets scope(it changes class as seen in directive).
Why is directive not picking $scope.loaded?
Message directive is loaded in other view:
<form class="form-horizontal" ng-submit="submit()">
<fieldset>
<!-- Form Name -->
<legend>Contact us</legend>
<!-- Text input-->
<div class="form-group">
<label class="col-md-4 control-label" for="textinput">Your name</label>
<div class="col-md-4">
<input id="name" name="textinput" type="text" placeholder="name" class="form-control input-md" ng-model="model.name" required>
</div>
</div>
<!-- Text input-->
<div class="form-group">
<label class="col-md-4 control-label" for="textinput">Your email</label>
<div class="col-md-4">
<input id="from" name="textinput" type="email" placeholder="email" class="form-control input-md" ng-model="model.from" required>
</div>
</div>
<!-- Textarea -->
<div class="form-group">
<label class="col-md-4 control-label" for="textarea">Content</label>
<div class="col-md-4">
<textarea class="form-control" id="content" name="textarea" ng-model="model.content" required>your message to us</textarea>
</div>
</div>
<!-- Button -->
<div class="form-group">
<label class="col-md-4 control-label" for="singlebutton"></label>
<div class="col-md-4">
<button id="singlebutton" name="singlebutton" class="btn btn-primary" ng-click>Submit</button>
</div>
</div>
<message-directive></message-directive>
</fieldset>
</form>
I have a custom directive:
(function (angular) {
angular.module('app')
.directive('messageDirective', [function () {
return {
restrict: 'E',
templateUrl: 'partials/message-directive',
scope: true,
link: function (scope) {
scope.loaded = true;
}
};
}]);
})(angular);
TemplateUrl:
<div class="form-group">
<label class="col-md-4 control-label" for="message"></label>
<div class="col-md-4">
<div ng-show="loaded" ng-class="sent ? 'alert alert-success' : 'alert alert-danger'">
{{message}}
</div>
</div>
</div>
Controller:
(function (angular) {
angular.module('app')
.controller('contactController', [
'$scope', 'contactService', function ($scope, contactService) {
$scope.model = {};
$scope.loaded = false;
var successCallback = function () {
$scope.message = "Sent!";
$scope.sent = true;
}
var errorCallback = function () {
$scope.message = "Error!";
$scope.sent = false;
}
$scope.submit = function() {
contactService.createContact($scope.model).then(successCallback, errorCallback);
}
}]);
})(angular);
the directive load after the controller .so your code
link: function (scope) {
scope.loaded = true;
}
rewrite the $scope.loaded
return {
restrict: 'E',
templateUrl: 'partials/message-directive',
scope: false,
link: function (scope) {
scope.loaded = true;
}
};

Why is my $scope not working?

I'm newbie in angularJS. I have finished phone-cat tutorial on the official angular document. I am trying to create some new feature for it such as ( create a new item , edit ... ) Assume that I created api for this.
app/phone-create/phone-create.module.js
angular.module('phoneCreate', ['core.phone'])
app/phone-create/phone-create.component.js
angular.module('phoneCreate')
.component('phoneCreate', {
templateUrl: 'phone-create/phone-create.template.html',
controller: ['Phone', '$scope',
function PhoneCreateController(Phone, $scope) {
var self = this;
var data = {
name: $scope.name,
description: $scope.description,
kind: $scope.kind
}
self.create = function () {
console.log(data); // {name : underfined , desciprion : underfined , kind : underfined}
}
}
]
});
app/phone-create/phone-create.template.html
<div class="row">
<div class="form-horizontal col-md-8">
<div class="form-group">
<label class="control-label col-sm-4" for="name">Name</label>
<div class="col-sm-8">
<input type="text" ng-model="$ctrl.name" class="form-control" id="name" placeholder="Name">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-4" for="description">Description</label>
<div class="col-sm-8">
<input type="text" ng-model="$ctrl.description" class="form-control" id="description" placeholder="description">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-4" for="kind">Kind</label>
<div class="col-sm-8">
<input type="text" ng-model="$ctrl.kind" class="form-control" id="kind" placeholder="Kind">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-8">
<button type="submit" ng-click="$ctrl.create()" class="btn btn-default">Create</button>
</div>
</div>
</div>
</div>
When I click Create , I want to fields in input will be accessed by scope in controller but it is underfined. I don't know why and how to fix. Please help me!.
Let's take a look at these three lines:
<input type="text" ng-model="$ctrl.name" class="form-control" id="name" placeholder="Name">
<input type="text" ng-model="$ctrl.description" class="form-control" id="description" placeholder="description">
<input type="text" ng-model="$ctrl.kind" class="form-control" id="kind" placeholder="Kind">
They have ng-models: $ctrl.name, $ctrl.description, $ctrl.kind. Your component doesn't declare those variables.
Change them to $ctrl.data.name, $ctrl.data.description, $ctrl.data.kind and modify your component:
angular.module('phoneCreate')
.component('phoneCreate', {
templateUrl: 'phone-create/phone-create.template.html',
controller: ['Phone', '$scope',
function PhoneCreateController(Phone, $scope) {
var self = this;
self.data = {
name: "",
description: "",
kind: ""
};
self.create = function () {
console.log(self.data);
};
}
]
});
OPTION 1 :
angular.module('phoneCreate')
.component('phoneCreate', {
templateUrl: 'phone-create/phone-create.template.html',
controller: ['Phone', '$scope',
function PhoneCreateController(Phone, $scope) {
var self = this;
self.create = function () {
console.log(self.name); // {name : underfined , desciprion : underfined , kind : underfined}
}
}
]
});
OPTION 2 :
angular.module('phoneCreate')
.component('phoneCreate', {
templateUrl: 'phone-create/phone-create.template.html',
controller: ['Phone', '$scope',
function PhoneCreateController(Phone, $scope) {
var self = this;
// No need to initialise self.data
self.data = {
name: '',
description: '',
kind: ''
}
self.create = function () {
console.log(self.data);
console.log(self.data.name);
}
}
]
});
HTML :
<div class="row">
<div class="form-horizontal col-md-8">
<div class="form-group">
<label class="control-label col-sm-4" for="name">Name</label>
<div class="col-sm-8">
<input type="text" ng-model="$ctrl.data.name" class="form-control" id="name" placeholder="Name">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-4" for="description">Description</label>
<div class="col-sm-8">
<input type="text" ng-model="$ctrl.data.description" class="form-control" id="description" placeholder="description">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-4" for="kind">Kind</label>
<div class="col-sm-8">
<input type="text" ng-model="$ctrl.data.kind" class="form-control" id="kind" placeholder="Kind">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-8">
<button type="submit" ng-click="$ctrl.create()" class="btn btn-default">Create</button>
</div>
</div>
</div>
</div>

Can't hide form from inside itself changing showForm value because it is undefined

I was making a small "Reading List" application following guides of Soup to Bits: Shaping up with Angular.js video
I didn't like the way they put "Cancel" button at the top and just for practice decided to move it inside the form. I figured out how to make it work (click on 'Cancel' hid the form using expression ng-click="reviewFormCtrl.showForm = false"). It worked until guys from CodeSchool made an isolated scope
directive('reviewForm', function(){
return {
restrict: "E",
templateUrl: "partials/review-form.html",
replace: true,
controller: function() {
this.showForm = false;
this.book = {genres:{}};
this.addReview = function(form) {
books.push(this.book);
this.book = {genres:{}};
form.$setPristine();
}
},
controllerAs: 'reviewFormCtrl',
scope: {
books: '=',
genres: '='
}
}
})
From that point my 'Cancel' button stopped working. Console says that ReviewFormCtrl and ReviewFormCtrl.showForm are undefined. I can't figure out how to change that value from inside the scope I'm in.
Below is my app.html and app.js
(function() {
'use strict';
// Declare app level module which depends on views, and components
angular.module('readingList', []).
controller('ReadingListController', function(){
this.books = books;
this.genres = genres;
}).
directive('bookGenres', function(){
return {
restrict: "E",
templateUrl: "partials/book-genres.html",
scope: {
genres: "="
}
}
}).
directive('bookCover', function(){
return {
restrict: "E",
templateUrl: "partials/book-cover.html",
replace: true
}
}).
directive('reviewForm', function(){
return {
restrict: "E",
templateUrl: "partials/review-form.html",
replace: true,
controller: function() {
this.showForm = false;
this.book = {genres:{}};
this.addReview = function(form) {
books.push(this.book);
this.book = {genres:{}};
form.$setPristine();
}
},
controllerAs: 'reviewFormCtrl',
scope: {
books: '=',
genres: '='
}
}
})
;
var genres = [ 'fable', 'fantasy', 'fiction', 'folklore', 'horror', 'humor', 'legend', 'metafiction', 'mystery', 'mythology', 'non-fiction', 'poetry' ];
var books = [
{
title: 'A Game of Thrones: A Song of Ice and Fire',
author: 'George R.R. Martin',
isbn: '0553593714',
review: 'The most inventive and entertaining fantasy saga of our time—warrants one hell of an introduction. I loved this book!',
rating: 4,
genres: { 'non-fiction': true, fantasy: true }
},{
title: 'HTML for Babies',
author: 'John C Vanden-Heuvel Sr',
isbn: '0615487661',
review: "It's never too early to be standards compliant! I taught my little one mark-up in under one hour!",
rating: 5,
genres: { fiction: true }
},{
title: 'A is for Array',
author: 'Brandon J Hansen',
isbn: '1489522212',
review: 'A is for Array is the ABC book for future programmers. Filled with fun illustrations and simple real-world examples, my children loved seeing my world intertwined with theirs!',
rating: 4,
genres: { fiction: true }
},{
title: 'The Dragon Reborn',
author: 'Robert Jordan',
isbn: '0812513711',
review: 'The Wheel weaves as the Wheel wills, and we are only the thread of the Pattern. Moiraine',
rating: 4,
genres: { 'non-fiction': true, fantasy: true }
}
];
})();
<h1>Angular Reading List of Awesome</h1>
<div class="row" ng-controller="ReadingListController as readingListCtrl">
<button class="btn btn-default" ng-click="reviewFormCtrl.showForm = !reviewFormCtrl.showForm" ng-hide="reviewFormCtrl.showForm">{{reviewFormCtrl.showForm ? "Cancel" : "Create a Review"}}</button>
<hr />
<review-form books="readingListCtrl.books" genres="readingListCtrl.genres" ng-show="reviewFormCtrl.showForm"></review-form>
<hr ng-show="reviewFormCtrl.showForm"/>
<ul class="list-unstyled col-sm-8">
<li class="book row" ng-repeat="book in readingListCtrl.books">
<!-- Book cover goes here -->
<book-cover></book-cover>
<div class="col-sm-9">
<h3>{{book.title}}</h3>
<cite class="text-muted">Written by {{book.author}}</cite>
<p>{{book.review}}</p>
<!-- Put genre here -->
<book-genres genres="book.genres"></book-genres>
</div>
</li>
</ul>
</div>
Here's a review-form.html
<form name="reviewForm" class="form-horizontal" ng-submit="reviewFormCtrl.addReview(reviewForm)">
<section class="row well live-preview" ng-show="reviewFormCtrl.book.isbn">
<aside class="col-sm-3">
<a href="http://www.amazon.com/gp/product/{{reviewFormCtrl.book.isbn}}">
<img src="http://images.amazon.com/images/P/{{reviewFormCtrl.book.isbn}}.01.ZTZZZZZZ.jpg" alt="Cover of Book" class="full">
</a>
<p>{{reviewFormCtrl.book.rating}}/5</p>
</aside>
<div class="col-sm-9">
<h3>
<a href="http://www.amazon.com/gp/product/{{reviewFormCtrl.book.isbn}}">
{{reviewFormCtrl.book.title}}
</a>
</h3>
<cite class="text-muted">Written by {{reviewFormCtrl.book.author}}</cite>
<p>{{reviewFormCtrl.book.review}}</p>
<book-genres genres="reviewFormCtrl.book.genres"></book-genres>
</div>
</section>
<div class="input-container">
<fieldset class="form-group">
<label for="title" class="col-sm-2 control-label">Title:</label>
<span class="col-sm-9">
<input type="text" class="form-control" id="title"
placeholder="Book Title" ng-model="reviewFormCtrl.book.title">
</span>
</fieldset>
<fieldset class="form-group">
<label for="isbn" class="control-label col-sm-2">ISBN:</label>
<span class="col-sm-9">
<input type="text" id="isbn" class="form-control"
maxLength="10" placeholder="ISBN-10" ng-model="reviewFormCtrl.book.isbn">
</span>
</fieldset>
<fieldset class="form-group">
<label class="control-label col-sm-2" for="author">Author</label>
<span class="col-sm-9">
<input type="text" id="author" class="form-control"
placeholder="Name of the Author" ng-model="reviewFormCtrl.book.author"></span>
</fieldset>
<fieldset class="form-group">
<label class="control-label col-sm-2" for="review">Review</label>
<span class="col-sm-9">
<textarea id="review" class="form-control" cols="30" rows="3"
placeholder="Book Review" ng-model="reviewFormCtrl.book.review"></textarea>
</span>
</fieldset>
<fieldset class="form-group">
<label for="rating" class="control-label col-sm-2">Rating:</label>
<span class="col-sm-9">
<select class="form-control" id="rating" value="5" ng-model="reviewFormCtrl.book.rating">
<option>5</option>
<option>4</option>
<option>3</option>
<option>2</option>
<option>1</option>
</select>
</span>
</fieldset>
<fieldset class="form-group">
<label class="control-label col-sm-2" >Genre:</label>
<div class="genre">
<label for="{{genre}}" class="genre-label form-control" ng-repeat="genre in genres">
<input type="checkbox" name="genre" id="{{genre}}" ng-model="reviewFormCtrl.book.genres[genre]"/>
{{genre}}
</label>
</div>
</fieldset>
<fieldset class="form-group">
<span class="col-sm-9 col-sm-offset-2 button-from-hell">
<button class="btn btn-primary">Save Review</button>
<button class="btn btn-default" ng-click="reviewFormCtrl.showForm = false" style="margin-right: 15px;">Cancel</button>
</span>
</fieldset>
</div>
</form>
You are referencing the reviewFormCtrl outside of the review-form directive on multiple occasions. Both here:
<button class="btn btn-default" ng-click="reviewFormCtrl.showForm = !reviewFormCtrl.showForm" ng-hide="reviewFormCtrl.showForm">{{reviewFormCtrl.showForm ? "Cancel" : "Create a Review"}}</button>
and here:
<hr ng-show="reviewFormCtrl.showForm"/>
You don't have access to it in those places. If you wish to control the directives visibility then perhaps create the showForm property on the readingListCtrl controller instead, double bind it into the directive like so:
<review-form books="readingListCtrl.books" genres="readingListCtrl.genres" visibility="readingListCtrl.showForm"></review-form>
Then add it to the scope property on the directive:
scope: {
books: '=',
genres: '=',
visibility: '='
}
And finally applying it directly to the form element within your template:
<form ng-show="reviewFormCtrl.visibility" name="reviewForm" class="form-horizontal" ng-submit="reviewFormCtrl.addReview(reviewForm)">
And of course updating your Cancel button to change visibility now instead.

AngularJS custom directives

I'm creating template for text inputing using angular directives.
Directive will receive 3 attributes: title, placeholder and model.
I need attribte model to be implemented into atribute ng-model in directive template.
For example:
if i create element with next attributes
<ng-text-input model="test" title="First name" placeholder="First name"></ng-text-input>
result will be next:
<div class="form-group">
<label class="col-sm-2 control-label">First name</label>
<div class="col-sm-9">
<input ng-model="test" type="text" class="form-control" placeholder="First name">
</div>
</div>
And how can i use model "test" in parent scope?
Thanks
upadete after #Maxdow comment:
directive declaration:
app.directive('ngTextInput', function(){
return {
restrict : 'AE',
scope: {
title: '#',
placeholder : '#',
myModel: '=ngModel'
},
templateUrl : 'ng-textInput.html'
}
});
template:
<script type="text/ng-template" id="ng-textInput.html">
<div class="form-group">
<label class="col-sm-2 control-label">{{title}}</label>
<div class="col-sm-9">
<input ng-model="myModel" type="text" class="form-control" placeholder={{placeholder}}>
</div>
</div>
</script>
using:
<ng-text-input ng-model="test" title="First name" placeholder="First name"></ng-text-input>
but result is still:
<div class="form-group">
<label class="col-sm-2 control-label ng-binding">First name</label>
<div class="col-sm-9">
<input ng-model="myModel" type="text" class="form-control ng-pristine ng-valid" placeholder="First name">
</div>
</div>
What am i doing wrong?
In your directive bind your attribute with ngModel :
app.directive('myDirective', function() {
return {
restrict: 'AE',
scope: {
myModel: '=ngModel'
},
template:'<input ng-model="myModel"/>'
}});
You should be able to use is from your HTML like this :
<my-directive ng-model="whatyouwant"></my-directive>
An example : http://jsfiddle.net/maxdow/6GU6x/

Resources