I have a component as following :
.component('myLink', {
bindings: {
linkEntity: '=',
constraints: '=?',
fieldName: '#',
standalone: '#',
adherence: '#',
searchMinLength: '<',
searchHandler: '&',
viewItemHandler: '&',
onSelectItemHandler: '&',
hiddenFields: '#',
formName: '#',
date: '<?',
constraintsJson: '#'
},
require: {
parent: '?^form'
},
templateUrl: 'my-link-component.html',
controller: 'MyLinkController',
controllerAs: 'slink'
});
The template url :
<ng-form name="{{slink.linkFormName}}">
<fieldset class="link-fieldset">
<legend>
<md-icon>link</md-icon>
</legend>
<div layout="row" flex ng-if="slink.isFormLoaded">
<md-button print-remove ng-if="!slink.constraints.readOnly" ng-click="slink.querySearch(' ')" class="md-icon-button md-primary">
<md-icon aria-label="Tout voir">view_headline</md-icon>
<md-tooltip md-direction="right">Afficher toute la liste de : {{slink.uiName | lowercase}}</md-tooltip>
</md-button>
<md-autocomplete flex ng-disabled="slink.constraints.readOnly" md-selected-item="slink.selectedItem" md-search-text="slink.searchText" md-selected-item-change="slink.changeItem(item)" md-items="item in slink.querySearch(slink.searchText)" md-min-length="1" md-no-cache="slink.noCache" md-select-on-match=true md-autoselect=true md-item-text="slink.itemToText(item)" md-input-name="{{slink.property}}" md-input-id="simple-link-component-{{slink.property}}-{{slink.autoId}}-input" md-floating-label="{{slink.floatingLabel}}" md-select-on-focus style="background: none;">
<md-item-template>
<span md-highlight-text="slink.searchText === ' ' ? slink.itemToText(slink.selectedItemStore) : slink.searchText" md-highlight-flags="^i">
{{item.domainObjectDescription}}
</span>
</md-item-template>
<md-not-found>
<div style="width: 100%;">{{slink.notFoundMsg}}
</div>
</md-not-found>
<div ng-messages="slink.errorMessage" ng-if="!slink.constraints.readOnly">
<div ng-messages-include='messages/messages.html'></div>
</div>
</md-autocomplete>
<md-button print-remove ng-if="slink.standalone !== 'list' && !slink.constraints.readOnly" ng-disabled="!slink.selectedItem" class="md-icon-button md-primary" ng-click="slink.viewItem()">
<md-icon aria-label="Voir le détail">visibility</md-icon>
<md-tooltip md-direction="left">Voir le détail de : {{slink.uiName | lowercase}}</md-tooltip>
</md-button>
</div>
</fieldset>
</ng-form>
In the controller I'm trying to access the form as following :
function onInitComponent() {
//...
console.log($scope[slink.linkFormName]);
//...
}
But I always get undefined.
In the other hand, from the changeItem function, which triggers after I made a change on the component it's defined.
How can I access my form when I initilize my component ?
As discussed in this thread you can use $postLink() lifecycle hook to initially access your form in your components controller, since it is called after this controller's element and its children have been linked so we can be sure the form was initialized. See the example below:
(function (angular) {
'use strict';
angular.module('myApp', [])
.controller('MyCtrl', ['$scope', function MyCtrl($scope) {
this.id = 1;
}]);
})(angular);
(function (window, angular) {
'use strict';
var myLink = {
bindings: {
id: '<',
linkFormName: '#'
},
templateUrl: 'my-link-component.tmpl.html',
controller: 'MyLinkController',
controllerAs: 'slink'
};
angular.module('myApp')
.component('myLink', myLink);
})(window, angular);
(function (angular) {
'use strict';
angular
.module('myApp')
.controller('MyLinkController', MyLinkController);
MyLinkController.$inject = ['$scope'];
function MyLinkController($scope) {
var slink = this;
//component lifecycle hooks
slink.$onInit = onInit;
slink.$postLink = postLink;
function onInit() {
console.log('onInit: ', $scope[slink.linkFormName]);
}
function postLink() {
console.log('postLink: ',$scope[slink.linkFormName]);
}
}
})(angular);
<script src="//code.angularjs.org/1.6.2/angular.js"></script>
<div ng-app="myApp">
<div ng-controller="MyCtrl as myCtrl">
<my-link id="myCtrl.id" link-form-name='myLinkForm'></my-link>
</div>
<script type="text/ng-template" id="my-link-component.tmpl.html">
<ng-form name="{{slink.linkFormName}}">
<fieldset class="link-fieldset">
<legend>
<md-icon>link</md-icon>
</legend>
</fieldset>
</ng-form>
</script>
</div>
Related
I'm using $mdDialog and I specified a Controller which is present in another js file.
Parent Js Controller:
$scope.AddDesignationPrompt = function(ev) {
$mdDialog.show({
controller: 'AddDesignationPromptController',
templateUrl: './Employee/Views/AddDesignation.tmpl.html',
parent: angular.element(document.body),
targetEvent: ev,
clickOutsideToClose:true,
fullscreen: true // Only for -xs, -sm breakpoints.
})
.then(function(answer) {
$scope.GetPriliminaryData();
}, function() {
$scope.status = 'You cancelled the dialog.';
});
};
Dialog Controller:
app.controller('AddDesignationPromptController', function ($scope, $rootScope, $mdDialog, $window, HTTPService) {
$scope.loadUpData = {
State: [],
Department: [],
Designation: []
};
HTTPService.getPriliminaryRegData().then(function (result) {
if ((result != undefined) && (result != null)) {
$scope.loadUpData = {
State: [],
Department: result.Result.Department,
Designation: []
};
console.log("Inside");
console.log($scope.loadUpData);
}
});
console.log("Outside");
console.log($scope.loadUpData);
$scope.hide = function() {
$mdDialog.hide();
};
$scope.cancel = function() {
$mdDialog.cancel();
};
$scope.answer = function(answer) {
$mdDialog.hide(answer);
};
});
View:
<md-dialog aria-label="Mango (Fruit)">
<form ng-cloak>
<md-toolbar>
<div class="md-toolbar-tools">
<h2>New Department</h2>
<span flex></span>
<md-button class="md-icon-button" ng-click="cancel()">
<md-icon md-svg-src="./Employee/images/Close.svg" aria-label="Close dialog"></md-icon>
</md-button>
</div>
</md-toolbar>
<md-dialog-content>
<div class="md-dialog-content">
<p>Enter the New Department</p>
<div class="controlItem">
<md-select ng-model="select.designation" ng-change="onDesignationChange(select.designation)" tabindex="9">
<md-option ng-repeat="key in loadUpData.Designation" value="{{key.DesignationId}}">{{key.Name}}</md-option>
</md-select>
</div>
</div>
</md-dialog-content>
<md-dialog-actions layout="row">
<span flex></span>
<md-button ng-click="answer('not useful')">
Not Useful
</md-button>
<md-button ng-click="answer('useful')">
Useful
</md-button>
</md-dialog-actions>
</form>
</md-dialog>
Its coming in controller level, but its not loading in md-select. Kindly assist me how to load the collection in the View.
You are looping over loadUpData.Designation which is always set to empty array [], so nothing will be ever displayed. The only data that is populated in your HTTPService promise resolve is loadUpData.Department, but you never print it in your HTML.
if you have Designation in result, than populate it, something like:
HTTPService.getPriliminaryRegData().then(function (result) {
if (result && result.Result) {
$scope.loadUpData = {
State: [],
Department: result.Result.Department,
Designation: result.Result.Designation
};
console.log("Inside");
console.log($scope.loadUpData);
}
});
I have 4 files, View, a Module, a controller and a factory :
Module : project.module.js
(function () {
'use strict';
angular.module('BlurAdmin.pages.projects', [])
.config(routeConfig);
/** #ngInject */
function routeConfig($stateProvider, $urlRouterProvider) {
$stateProvider
.state('projects', {
url: '/projects',
template : '<ui-view autoscroll="true" autoscroll-body-top></ui-view>',
abstract: true,
title: 'Les projets',
Controller : 'ProjectController',
sidebarMeta: {
icon: 'ion-compose',
order: 250,
},
.state('projects.add', {
url: '/add',
templateUrl: 'app/pages/projects/add/addProject.html',
title: 'Ajouter un projet',
sidebarMeta: {
order: 800,
},
.state('projects.list', {
url: '/list',
templateUrl: 'app/pages/projects/list/listProjects.html',
title: 'List',
sidebarMeta: {
order: 900,
},
});
$urlRouterProvider.when('/projects','/projects/list');
}
})();
Controller : ProjectController.js
(function(){
'use strict';
angular.module('BlurAdmin.pages.projects')
.controller('ProjectController', ProjectController);
function ProjectController($state, $stateParams, $log, $scope, projectFactory) {
<!-- Value to show -->
$scope.addMessage = "see ME";
...}
})();
Factory : projectFactory.js
function(){
'use strict';
angular.module('BlurAdmin.pages.projects')
.factory('projectFactory', projectFactory);
function projectFactory($http, $stateParams) {
var factory = {};
....
}})();
View : addProject.html
<div class="col-md-6">
<div
ba-panel
ba-panel-title="Ajouter un projet"
ba-panel-class="with-scroll">
<form name="ProjectForm" ng-submit="setProject()" ng-init="getProjectById()">
<!-- Value to show -->
Show me the add message : {{addMessage}}
<div class="form-group">
<label for="titre">Titre du projet</label>
<input type="text" class="form-control" id="titre" placeholder="Titre">
</div>
<div class="form-group" ng-controller="datepickerpopupCtrl">
<label>Date de début: <em>{{dt | date:'fullDate' }}</em></label>
<p class="input-group">
<input type="text" class="form-control" uib-datepicker-popup="{{format}}" datepicker-options="options" ng-model="dt" is-open="opened" ng-required="true" close-text="Close" alt-input-formats="altInputFormats" show-button-bar="false" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="open()"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</p>
</div>
<section class="col-md-6 col-lg-3">
<button progress-button="progressFunction()" pb-style="rotate-side-up" class="btn btn-danger">Submit</button>
</section>
</form>
</div>
</div>
</div>
Now the state is loaded perfectly and everything is working fine but when I try to load a variable from the controller in the View it doesn't show.
And I'm loading the scripts in the index page :
<script src="app/pages/projects/projects.modules.js"></script>
<script src="app/pages/projects/projectFactory.js"></script>
<script src="app/pages/projects/ProjectController.js"></script>
<script src="app/pages/projects/add/addProject.html"></script>
P.S: I have an error and I don't know if it's related or not :
projects.html:2 Uncaught SyntaxError: Unexpected token <
P.S: I'm using this BootsTrap template
To become more dynamic my directive decided to include the category field that makes the selection of the type of template to be displayed. As it is only a select thought of using the switch - ng instead of several html files. (google translate)
Plunker: http://plnkr.co/edit/fnCJj15XJN1kQvKq1OtZ?p=preview
index.html
<div ng-controller="MainCtrl">
<sg-combo
selected-item="selectedItem" categoria="filtro">
</sg-combo>
{{selectedItem}}
script.js
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.selectedItem = {value: null};
$scope.$watch('selectedItem',function(item){
if (item != null){
alert(item.nome); // does not display when updating
}
})
});
app.directive('sgCombo', function(){
function link(scope, elem, attrs){
scope.dados = [
{'codigo':1, 'nome':'teste1'},
{'codigo':2, 'nome':'teste2'},
{'codigo':3, 'nome':'teste3'}
];
}
return {
restrict: 'E',
scope: {
selectedItem: '=',
categoria: '#'
},
link: link,
templateUrl:"sg-combo.html"
}
})
sg-combo.html
<div ng-switch="categoria">
<div ng-switch-when="filtro" class="col-sm-4 control-label">
<div class="col-sm-4 control-label">
<label>{{label}}</label>
<select ng-model="selectedItem.value" ng-options="item.nome for item in dados" class="form-control"></select>
</div>
</div>
<div ng-switch-when="anexo" class="col-sm-4 control-label">
<div class="col-sm-4 control-label">
<label>{{label}}</label>
<select ng-model="selectedItem.value" ng-options="item.nome for item in dados" class="form-control"></select>
</div>
</div>
</div>
Try to make 'selectedItem' a part of an object.
For instance:
In controller:
$scope.options = {'selectedItem': someItem};
In template:
ng-model="options.selectedItem"
ng-switch adds a scope and you should use '.' in ng-model.
I have a custom directive : myContent
'use strict';
angular.module('myModule').directive('myContent', function() {
return {
restrict: 'E',
templateUrl: 'myContent.html',
controller: function($scope){
$scope.selectedContents = {
priceOrTransactionOption : null,
yearlyOrMonthly : 'Yearly',
contentIndicator : null
};
$scope.comboContent = {
priceOrTransactionOption : ['By Price Range', 'By Transactions'],
yearlyOrMonthly : ['Yearly', 'Monthly'],
contentIndicator : ['Active configuration', 'Next Configuration']
};
},
controllerAs: 'myContentCtrl'
};
});
And I'm using this same directive in multiple places :
<div class="tab-content col-lg-10">
<my-content></my-content>
</div>
<div class="tab-content col-lg-10">
<my-content></my-content>
</div>
<div class="tab-content col-lg-10">
<my-content></my-content>
</div>
And my html page for the directive (myContent.html) is having some data with :
<div class="row no-left-padding">
<div class="col-lg-3 no-left-padding">
<select class="form-control" ng-model="selectedContent.priceOrTransactionOption"
ng-options="keyOption as keyOption for keyOption in comboContent.priceOrTransactionOption">
</select>
</div>
<div class="col-lg-3 no-left-padding">
<select class="form-control" ng-model="selectedContent.yearlyOrMonthly" ng-disabled = "true"
ng-options="interval as interval for interval in comboContent.yearlyOrMonthly">
</select>
</div>
<div class="col-lg-3 no-left-padding">
<select class="form-control" ng-model="selectedContent.contentIndicator"
ng-options="indicator as indicator for indicator in comboContent.contentIndicator">
</select>
</div>
</div>
But my problem is, when ever I'm changing the model in one directive, it reflects in each directives.
How can I use the same directive, and map each with different models?
I had tried with wadding one attribute to my custom directive:
<div class="tab-content col-lg-10">
<my-content category="type1"></my-content>
</div>
<div class="tab-content col-lg-10">
<my-content category="type2"></my-content>
</div>
<div class="tab-content col-lg-10">
<my-content category="type3"></my-content>
</div>
But still I'm confused with where should I map the category for getting isolated object.
You need to add Isolated scope to your directive. This effectively allows it to have its own set of properties:
angular.module('myModule').directive('myContent', function() {
return {
restrict: 'E',
templateUrl: 'myContent.html',
scope: {
category:'='
},
controller: function($scope){
$scope.selectedContents = {
priceOrTransactionOption : null,
yearlyOrMonthly : 'Yearly',
contentIndicator : null
};
$scope.comboContent = {
priceOrTransactionOption : ['By Price Range', 'By Transactions'],
yearlyOrMonthly : ['Yearly', 'Monthly'],
contentIndicator : ['Active configuration', 'Next Configuration']
};
},
controllerAs: 'myContentCtrl'
};
});
You can then use your example above:
<div class="tab-content col-lg-10">
<my-content category="type1"></my-content>
</div>
And each one will work individually.
Take note though, when you add your properties of the isolated scope binding '='. There are a number of different types, '#', '=' and '&' as well as optional arguments. The naming of your scope property uses snake case. Rather than me giving you a full explanation, read the Angular developers guide on isolated scope
Try adding this in your directive definition:
restrict: 'E',
scope: {},
It appears what you want is to return selectedContents for each instance of the directive. To do this, you would use angular two way binding to create a link between your directive and the page content.
angular.module('myModule').directive('myContent', function() {
return {
restrict: 'E',
templateUrl: 'myContent.html',
scope: {
selectedContents: '='
},
controller: function($scope){
$scope.selectedContents = {
priceOrTransactionOption : null,
yearlyOrMonthly : 'Yearly',
contentIndicator : null
};
....
now, you can refer to the selectedContents as a parameter on the directive.
<div class="tab-content col-lg-10">
<my-content selectedContents="someObject.selectedContents"></my-content>
</div>
<div class="tab-content col-lg-10">
<my-content selectedContents="someOtherObject.selectedContents"></my-content>
</div>
The SignupCtrl controller is not binding to signup view. Even when i press the submit button it don't work. But when i place ng-controller=SignupCtrl in the form tag it works. Just wondering why ui-router state parameter controller was not working.
index.html
<html class="no-js" ng-app="mainApp" ng-controller="MainCtrl">
<head> ....
</head>
<body class="home-page">
<div ui-view="header"></div>
<div ui-view="content"></div>
<div ui-view="footer"></div>
...
signup.html
<div class="form-container col-md-5 col-sm-12 col-xs-12">
<form class="signup-form">
<div class="form-group email">
<label class="sr-only" for="signup-email">Your email</label>
<input id="signup-email" type="email" ng-model="user.email" class="form-control login-email" placeholder="Your email">
</div>
<!--//form-group-->
<div class="form-group password">
<label class="sr-only" for="signup-password">Your password</label>
<input id="signup-password" type="password" ng-model="user.password" class="form-control login-password" placeholder="Password">
</div>
<!--//form-group-->
<button type="submit" ng-click="createUser()" class="btn btn-block btn-cta-primary">Sign up</button>
<p class="note">By signing up, you agree to our terms of services and privacy policy.</p>
<p class="lead">Already have an account? <a class="login-link" id="login-link" ui-sref="login">Log in</a>
</p>
</form>
</div><!--//form-container-->
app.js
angular
.module('mainApp', [
'services.config',
'mainApp.signup'
])
.config(['$urlRouterProvider', function($urlRouterProvider){
$urlRouterProvider.otherwise('/');
}])
signup.js
'use strict';
/**
* #ngdoc function
* #name mainApp.signup
* #description
* # SignupCtrl
*/
angular
.module('mainApp.signup', [
'ui.router',
'angular-storage'
])
.config(['$stateProvider', function($stateProvider){
$stateProvider.state('signup',{
url: '/signup',
controller: 'SignupCtrl',
views: {
'header': {
templateUrl: '/pages/templates/nav.html'
},
'content' : {
templateUrl: '/pages/signup/signup.html'
},
'footer' : {
templateUrl: '/pages/templates/footer.html'
}
}
});
}])
.controller( 'SignupCtrl', function SignupController( $scope, $http, store, $state) {
$scope.user = {};
$scope.createUser = function() {
$http({
url: 'http://localhost:3001/users',
method: 'POST',
data: $scope.user
}).then(function(response) {
store.set('jwt', response.data.id_token);
$state.go('home');
}, function(error) {
alert(error.data);
});
}
});
There is a working plunker. Firstly, check this Q & A:
Are there different ways of declaring the controller associated with an Angular UI Router state
Where we can see, that
controller does not belong to state. It belongs to view!
This should be the state definition:
$stateProvider.state('signup',{
url: '/signup',
//controller: 'SignupCtrl',
views: {
'header': {
templateUrl: 'pages/templates/nav.html'
},
'content' : {
templateUrl: 'pages/signup/signup.html',
controller: 'SignupCtrl',
},
'footer' : {
templateUrl: 'pages/templates/footer.html'
}
}
});
Check it here
You need a template to bind a controller.
In the docs ui-router Controllers
Controllers
You can assign a controller to your template. Warning: The controller
will not be instantiated if template is not defined.