diff --git a/dashboard/src/app/factories/create-factory/create-factory.controller.ts b/dashboard/src/app/factories/create-factory/create-factory.controller.ts
index afa8e3c375..0565796bc6 100644
--- a/dashboard/src/app/factories/create-factory/create-factory.controller.ts
+++ b/dashboard/src/app/factories/create-factory/create-factory.controller.ts
@@ -22,7 +22,7 @@ export class CreateFactoryCtrl {
private $log: ng.ILogService;
private cheAPI: CheAPI;
private cheNotification: CheNotification;
- private lodash: _.LoDashStatic;
+ private lodash: any;
private $filter: ng.IFilterService;
private $document: ng.IDocumentService;
private isLoading: boolean;
@@ -42,7 +42,7 @@ export class CreateFactoryCtrl {
* Default constructor that is using resource injection
* @ngInject for Dependency injection
*/
- constructor($location: ng.ILocationService, cheAPI: CheAPI, $log: ng.ILogService, cheNotification: CheNotification, $scope: ng.IScope, $filter: ng.IFilterService, lodash: _.LoDashStatic, $document: ng.IDocumentService) {
+ constructor($location: ng.ILocationService, cheAPI: CheAPI, $log: ng.ILogService, cheNotification: CheNotification, $scope: ng.IScope, $filter: ng.IFilterService, lodash: any, $document: ng.IDocumentService) {
this.$location = $location;
this.cheAPI = cheAPI;
this.$log = $log;
diff --git a/dashboard/src/app/factories/create-factory/create-factory.html b/dashboard/src/app/factories/create-factory/create-factory.html
index ceb806e1ac..de926a5dd4 100644
--- a/dashboard/src/app/factories/create-factory/create-factory.html
+++ b/dashboard/src/app/factories/create-factory/create-factory.html
@@ -27,10 +27,12 @@
ng-trim
ng-minlength="3"
ng-maxlength="20"
- ng-pattern="/^[ A-Za-z0-9_\-\.]+$/">
+ ng-pattern="/^[ A-Za-z0-9_\-\.]+$/"
+ unique-factory-name="">
Factory name may contain digits, latin letters, spaces, _ , . , - and should start only with digits, latin letters or underscores
The name has to be more than 3 characters long.
The name has to be less than 20 characters long.
+ This factory name is already used.
diff --git a/dashboard/src/app/factories/factory-details/information-tab/factory-information/factory-information.controller.ts b/dashboard/src/app/factories/factory-details/information-tab/factory-information/factory-information.controller.ts
index abf8064d57..bc1b9b9fa5 100644
--- a/dashboard/src/app/factories/factory-details/information-tab/factory-information/factory-information.controller.ts
+++ b/dashboard/src/app/factories/factory-details/information-tab/factory-information/factory-information.controller.ts
@@ -24,7 +24,7 @@ export class FactoryInformationController {
private $location: ng.ILocationService;
private $log: ng.ILogService;
private $timeout: ng.ITimeoutService;
- private lodash: _.LoDashStatic;
+ private lodash: any;
private $filter: ng.IFilterService;
private timeoutPromise: ng.IPromise;
@@ -40,13 +40,14 @@ export class FactoryInformationController {
private workspaceName: string;
private stackId: string;
private workspaceConfig: any;
+ private origName: string;
/**
* Default constructor that is using resource injection
* @ngInject for Dependency injection
*/
constructor($scope: ng.IScope, cheAPI: CheAPI, cheNotification: CheNotification, $location: ng.ILocationService, $log: ng.ILogService,
- $timeout: ng.ITimeoutService, lodash: _.LoDashStatic, $filter: ng.IFilterService, $q: ng.IQService, confirmDialogService: any) {
+ $timeout: ng.ITimeoutService, lodash: any, $filter: ng.IFilterService, $q: ng.IQService, confirmDialogService: any) {
this.cheAPI = cheAPI;
this.cheNotification = cheNotification;
this.$location = $location;
@@ -93,6 +94,7 @@ export class FactoryInformationController {
this.environmentName = this.factory.workspace.defaultEnv;
this.copyOriginFactory = angular.copy(this.factory);
+ this.origName = this.factory.name;
if (this.copyOriginFactory.links) {
delete this.copyOriginFactory.links;
}
@@ -100,7 +102,7 @@ export class FactoryInformationController {
let factoryContent = this.$filter('json')(this.copyOriginFactory);
if (factoryContent !== this.factoryContent) {
if (!this.factoryContent) {
- this.editorLoadedPromise.then((instance) => {
+ this.editorLoadedPromise.then((instance: any) => {
this.$timeout(() => {
instance.refresh();
}, 500);
@@ -139,12 +141,29 @@ export class FactoryInformationController {
}
/**
- * Update factory data.
+ * Update factory name.
+ *
+ * @param {string} name new factory name.
+ * @raram {ng.IFormController} form
*/
- updateFactory(): void {
+ updateName(name: string, form: ng.IFormController): void {
+ if (form.$invalid) {
+ return;
+ }
+
+ this.copyOriginFactory.name = name;
+
+ this.updateFactory(form);
+ }
+
+ /**
+ * Update factory data.
+ * @param {ng.IFormController} form
+ */
+ updateFactory(form: ng.IFormController): void {
this.factoryContent = this.$filter('json')(this.copyOriginFactory);
- if (this.factoryInformationForm.$invalid || !this.isFactoryChanged()) {
+ if (form.$invalid || !this.isFactoryChanged()) {
return;
}
diff --git a/dashboard/src/app/factories/factory-details/information-tab/factory-information/factory-information.html b/dashboard/src/app/factories/factory-details/information-tab/factory-information/factory-information.html
index dbaa2e2d43..f2a04a274b 100644
--- a/dashboard/src/app/factories/factory-details/information-tab/factory-information/factory-information.html
+++ b/dashboard/src/app/factories/factory-details/information-tab/factory-information/factory-information.html
@@ -16,16 +16,16 @@
@@ -94,7 +95,7 @@
che-place-holder="Name of the workspace"
aria-label="Name of the workspace"
ng-model="factoryInformationController.copyOriginFactory.workspace.name"
- ng-change="factoryInformationController.updateFactory()"
+ ng-change="factoryInformationController.updateFactory(factoryInformationForm)"
required
ng-minlength="3"
ng-maxlength="20"
@@ -123,7 +124,7 @@
MACHINE: {{machineKey}}
+ che-on-change="factoryInformationController.updateFactory(factoryInformationForm)">
@@ -136,7 +137,7 @@
+ cdvy-on-change="factoryInformationController.updateFactory(factoryInformationForm)">
@@ -151,7 +152,7 @@
+ cdvy-on-change="factoryInformationController.updateFactory(factoryInformationForm)">
diff --git a/dashboard/src/components/api/che-factory.factory.ts b/dashboard/src/components/api/che-factory.factory.ts
index 452dbfe4b1..be21643199 100644
--- a/dashboard/src/components/api/che-factory.factory.ts
+++ b/dashboard/src/components/api/che-factory.factory.ts
@@ -532,6 +532,17 @@ export class CheFactory {
return this.factoriesById.get(factoryId);
}
+ /**
+ * Get the factory by factoryName and userId
+ * @param factoryName {string} the factory name
+ * @param userId {string} the user ID
+ * @returns factory {che.IFactory}
+ */
+ getFactoryByName(factoryName: string, userId: string): che.IFactory {
+ const key = `${userId}:${factoryName}`;
+ return this.factoriesByName.get(key);
+ }
+
/**
* Set the factory
* @param factory {che.IFactory}
diff --git a/dashboard/src/components/api/test/che-http-backend.ts b/dashboard/src/components/api/test/che-http-backend.ts
index 701b0143b5..f86a0cce7a 100644
--- a/dashboard/src/components/api/test/che-http-backend.ts
+++ b/dashboard/src/components/api/test/che-http-backend.ts
@@ -469,6 +469,9 @@ export class CheHttpBackend {
this.httpBackend.when('DELETE', '/api/factory/' + factory.id).respond(() => {
return [200, {success: true, errors: []}];
});
+ if (this.defaultUser) {
+ this.httpBackend.when('GET', `/api/factory/find?creator.userId=${this.defaultUser.id}&name=${factory.name}`).respond([factory]);
+ }
allFactories.push(factory);
}
diff --git a/dashboard/src/components/typings/che.d.ts b/dashboard/src/components/typings/che.d.ts
index e2222542a7..07b19bbf19 100755
--- a/dashboard/src/components/typings/che.d.ts
+++ b/dashboard/src/components/typings/che.d.ts
@@ -459,6 +459,7 @@ declare namespace che {
ide?: any;
button?: any;
policies?: any;
+ links: string[];
}
export interface IRegistry {
diff --git a/dashboard/src/components/validator/unique-factory-name-validator.directive.ts b/dashboard/src/components/validator/unique-factory-name-validator.directive.ts
new file mode 100644
index 0000000000..27540944e1
--- /dev/null
+++ b/dashboard/src/components/validator/unique-factory-name-validator.directive.ts
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2015-2017 Red Hat, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ */
+'use strict';
+
+import {CheAPI} from '../api/che-api.factory';
+
+interface IFactoryNameValidatorAsyncModelValidators extends ng.IAsyncModelValidators {
+ uniqueFactoryName: (modelValue: any, viewValue?: any) => ng.IPromise;
+}
+
+interface IFactoryNameValidatorAttributes extends ng.IAttributes {
+ uniqueFactoryName: string;
+}
+
+/**
+ * Defines a directive for checking if the factory name is not already taken
+ * @author Oleksii Kurinnyi
+ */
+export class UniqueFactoryNameValidator implements ng.IDirective {
+ $q: ng.IQService;
+ cheAPI: CheAPI;
+
+ restrict: string = 'A';
+ require: string = 'ngModel';
+
+ user: che.IUser;
+
+ /**
+ * Default constructor that is using resource
+ * @ngInject for Dependency injection
+ */
+ constructor (cheAPI: CheAPI, $q: ng.IQService) {
+ this.cheAPI = cheAPI;
+ this.$q = $q;
+
+ this.user = this.cheAPI.getUser().getUser();
+ }
+
+ /**
+ * Check that the name of workspace is unique
+ */
+ link($scope: ng.IScope, element: ng.IAugmentedJQuery, attributes: IFactoryNameValidatorAttributes, ngModel: ng.INgModelController) {
+
+ const asyncValidators = ngModel.$asyncValidators as IFactoryNameValidatorAsyncModelValidators;
+
+ // validate only input element
+ if ('input' === element[0].localName) {
+
+ asyncValidators.uniqueFactoryName = (modelValue: any, viewValue: any) => {
+
+ // create promise
+ const deferred = this.$q.defer();
+
+ if (!this.user) {
+ deferred.reject(false);
+ return deferred.promise;
+ }
+
+ // parent scope ?
+ let scopingTest = $scope.$parent;
+ if (!scopingTest) {
+ scopingTest = $scope;
+ }
+
+ const currentFactoryName = scopingTest.$eval(attributes.uniqueFactoryName);
+
+ if (!modelValue || modelValue === currentFactoryName) {
+ deferred.resolve(true);
+ } else if (this.cheAPI.getFactory().getFactoryByName(modelValue, this.user.id)) {
+ deferred.reject(false);
+ } else {
+ this.cheAPI.getFactory().fetchFactoryByName(modelValue, this.user.id).finally(() => {
+ if (this.cheAPI.getFactory().getFactoryByName(modelValue, this.user.id)) {
+ deferred.reject(false);
+ } else {
+ deferred.resolve(true);
+ }
+ });
+ }
+
+ // return promise
+ return deferred.promise;
+ };
+ }
+ }
+
+}
diff --git a/dashboard/src/components/validator/unique-factory-name-validator.spec.ts b/dashboard/src/components/validator/unique-factory-name-validator.spec.ts
new file mode 100644
index 0000000000..d33ddd9b53
--- /dev/null
+++ b/dashboard/src/components/validator/unique-factory-name-validator.spec.ts
@@ -0,0 +1,299 @@
+/*
+ * Copyright (c) 2015-2017 Red Hat, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ */
+'use strict';
+import {CheFactory} from '../api/che-factory.factory';
+import {CheAPIBuilder} from '../api/builder/che-api-builder.factory';
+import {CheHttpBackend} from '../api/test/che-http-backend';
+
+interface ITestRootScope extends ng.IRootScopeService {
+ factoryName: string;
+ myForm: ng.IFormController;
+}
+
+interface ITestFormController extends ng.IFormController {
+ name: ng.INgModelController;
+}
+
+/**
+ * Test the factory name uniqueness
+ * @author Oleksii Kurinnyi
+ */
+
+describe('unique-factory-name-validator >', function() {
+ let $rootScope: ITestRootScope,
+ $compile: ng.ICompileService,
+ myForm: ITestFormController;
+
+ /**
+ * Factory API
+ */
+ let cheFactory: CheFactory;
+
+ /**
+ * API builder.
+ */
+ let cheAPIBuilder: CheAPIBuilder;
+
+ /**
+ * Che backend
+ */
+ let cheHttpBackend: CheHttpBackend;
+
+ /**
+ * Backend for handling http operations
+ */
+ let $httpBackend: ng.IHttpBackendService;
+
+ beforeEach(angular.mock.module('userDashboard'));
+
+ beforeEach(inject((_$compile_: ng.ICompileService,
+ _$rootScope_: ITestRootScope,
+ _cheFactory_: CheFactory,
+ _cheAPIBuilder_: CheAPIBuilder,
+ _cheHttpBackend_: CheHttpBackend) => {
+ $rootScope = _$rootScope_;
+ $compile = _$compile_;
+ cheFactory = _cheFactory_;
+ cheAPIBuilder = _cheAPIBuilder_;
+ cheHttpBackend = _cheHttpBackend_;
+ $httpBackend = _cheHttpBackend_.getHttpBackend();
+
+ }));
+
+ afterEach(function() {
+ $httpBackend.verifyNoOutstandingExpectation();
+ $httpBackend.verifyNoOutstandingRequest();
+ });
+
+ describe('validate factory name >', function() {
+ const factoryName1 = 'factoryName1',
+ loadedFactoryName = factoryName1,
+ factoryName2 = 'factoryName2',
+ uniqueName = 'uniqueName',
+ userId = 'userId';
+
+ beforeEach(() => {
+ // setup default user
+ const user = cheAPIBuilder.getUserBuilder().withId(userId).build();
+ cheHttpBackend.setDefaultUser(user);
+
+ cheHttpBackend.usersBackendSetup();
+
+ // setup factories
+ const factoryId1 = 'factoryId1',
+ factory1 = cheAPIBuilder.getFactoryBuilder().withId(factoryId1).withName(factoryName1).build();
+ cheHttpBackend.addUserFactory(factory1);
+
+ const factoryId2 = 'factoryId2',
+ factory2 = cheAPIBuilder.getFactoryBuilder().withId(factoryId2).withName(factoryName2).build();
+ cheHttpBackend.addUserFactory(factory2);
+
+ cheHttpBackend.factoriesBackendSetup();
+
+ cheHttpBackend.setup();
+
+ // setup backend
+ $httpBackend.whenGET( `/api/factory/find?creator.userId=${userId}&name=${uniqueName}`).respond(404, {error: 'not found'});
+
+ // fetch first factory
+ cheFactory.fetchFactoryByName(factoryName1, userId);
+
+ // flush HTTP backend
+ $httpBackend.flush();
+ });
+
+ describe('initially factory has an unique name >', () => {
+
+ beforeEach(() => {
+ $rootScope.factoryName = uniqueName;
+
+ const element = angular.element(`
+
+`);
+ $compile(element)($rootScope);
+ myForm = $rootScope.myForm as ITestFormController;
+ });
+
+ it('the form should be valid >', () => {
+ // flush HTTP backend
+ $httpBackend.flush();
+
+ // check form (expect valid)
+ expect(myForm.name.$invalid).toBe(false);
+ expect(myForm.name.$valid).toBe(true);
+ });
+
+ it('the HTTP request should be made >', () => {
+ $httpBackend.expectGET(`/api/factory/find?creator.userId=${userId}&name=${uniqueName}`);
+
+ // flush HTTP backend
+ $httpBackend.flush();
+ });
+
+ describe('change name to non-unique, factory is already downloaded >', () => {
+
+ beforeEach(() => {
+ myForm.name.$setViewValue(loadedFactoryName);
+ });
+
+ it ('the form should be invalid >', () => {
+ // check form (expect invalid)
+ expect(myForm.name.$invalid).toBe(true);
+ expect(myForm.name.$valid).toBe(false);
+ });
+
+ it('the HTTP request should not be made >', () => {
+ spyOn(cheFactory, 'fetchFactoryByName');
+ expect(cheFactory.fetchFactoryByName).not.toHaveBeenCalled();
+ });
+
+ });
+
+ describe('change name to non-unique, factory is not downloaded yet >', () => {
+
+ it ('the form should be invalid >', () => {
+ myForm.name.$setViewValue(factoryName2);
+
+ // flush HTTP backend
+ $httpBackend.flush();
+
+ // check form (expect invalid)
+ expect(myForm.name.$invalid).toBe(true);
+ expect(myForm.name.$valid).toBe(false);
+ });
+
+ it('the HTTP request should be made >', () => {
+ $httpBackend.expectGET(`/api/factory/find?creator.userId=${userId}&name=${factoryName2}`);
+
+ myForm.name.$setViewValue(factoryName2);
+
+ // flush HTTP backend
+ $httpBackend.flush();
+ });
+
+ });
+
+ });
+
+ describe('initially factory has a non-unique name, factory is already downloaded >', () => {
+
+ beforeEach(() => {
+ $rootScope.factoryName = loadedFactoryName;
+
+ const element = angular.element(`
+
+`);
+ $compile(element)($rootScope);
+ myForm = $rootScope.myForm as ITestFormController;
+
+ $rootScope.$digest();
+ });
+
+ it('the form should be invalid >', () => {
+ // check form (expect invalid)
+ expect(myForm.name.$invalid).toBe(true);
+ expect(myForm.name.$valid).toBe(false);
+ });
+
+ it('the HTTP request should not be made >', () => {
+ spyOn(cheFactory, 'fetchFactoryByName');
+ expect(cheFactory.fetchFactoryByName).not.toHaveBeenCalled();
+ });
+
+ describe('change name to unique> ', () => {
+
+ it ('the form should be valid >', () => {
+ myForm.name.$setViewValue(uniqueName);
+
+ // flush HTTP backend
+ $httpBackend.flush();
+
+ // check form (expect valid)
+ expect(myForm.name.$invalid).toBe(false);
+ expect(myForm.name.$valid).toBe(true);
+ });
+
+ it('the HTTP request should be made >', () => {
+ $httpBackend.expectGET(`/api/factory/find?creator.userId=${userId}&name=${uniqueName}`);
+
+ myForm.name.$setViewValue(uniqueName);
+
+ // flush HTTP backend
+ $httpBackend.flush();
+ });
+
+ });
+
+ });
+
+ describe('initially factory has a non-unique name, factory is not downloaded yet >', () => {
+
+ beforeEach(() => {
+ $rootScope.factoryName = factoryName2;
+
+ const element = angular.element(`
+
+`);
+ $compile(element)($rootScope);
+ myForm = $rootScope.myForm as ITestFormController;
+ });
+
+ it('the form should be invalid >', () => {
+ // flush HTTP backend
+ $httpBackend.flush();
+
+ // check form (expect invalid)
+ expect(myForm.name.$invalid).toBe(true);
+ expect(myForm.name.$valid).toBe(false);
+ });
+
+ it('the HTTP request should be made >', () => {
+ $httpBackend.expectGET(`/api/factory/find?creator.userId=${userId}&name=${factoryName2}`);
+
+ // flush HTTP backend
+ $httpBackend.flush();
+ });
+
+ describe('change name to unique> ', () => {
+
+ it ('the form should be valid >', () => {
+ myForm.name.$setViewValue(uniqueName);
+
+ // flush HTTP backend
+ $httpBackend.flush();
+
+ // check form (expect valid)
+ expect(myForm.name.$invalid).toBe(false);
+ expect(myForm.name.$valid).toBe(true);
+ });
+
+ it('the HTTP request should be made >', () => {
+ $httpBackend.expectGET(`/api/factory/find?creator.userId=${userId}&name=${uniqueName}`);
+
+ myForm.name.$setViewValue(uniqueName);
+
+ // flush HTTP backend
+ $httpBackend.flush();
+ });
+
+ });
+
+ });
+
+ });
+
+});
diff --git a/dashboard/src/components/validator/validator-config.ts b/dashboard/src/components/validator/validator-config.ts
index 063e8a4d6b..b572338894 100644
--- a/dashboard/src/components/validator/validator-config.ts
+++ b/dashboard/src/components/validator/validator-config.ts
@@ -18,18 +18,20 @@ import {UniqueStackNameValidator} from './unique-stack-name-validator.directive'
import {CityNameValidator} from './city-name-validator.directive';
import {CustomAsyncValidator} from './custom-async-validator.directive';
import {UniqueTeamNameValidator} from './unique-team-name-validator.directive';
+import {UniqueFactoryNameValidator} from './unique-factory-name-validator.directive';
export class ValidatorConfig {
constructor(register: che.IRegisterService) {
- register.directive('gitUrl', GitUrlValidator)
- .directive('cityNameValidator', CityNameValidator)
- .directive('uniqueProjectName', UniqueProjectNameValidator)
- .directive('uniqueWorkspaceName', UniqueWorkspaceNameValidator)
- .directive('customValidator', CustomValidator)
- .directive('customAsyncValidator', CustomAsyncValidator)
- .directive('uniqueStackName', UniqueStackNameValidator)
- .directive('uniqueTeamName', UniqueTeamNameValidator);
+ register.directive('gitUrl', GitUrlValidator);
+ register.directive('cityNameValidator', CityNameValidator);
+ register.directive('uniqueProjectName', UniqueProjectNameValidator);
+ register.directive('uniqueWorkspaceName', UniqueWorkspaceNameValidator);
+ register.directive('customValidator', CustomValidator);
+ register.directive('customAsyncValidator', CustomAsyncValidator);
+ register.directive('uniqueStackName', UniqueStackNameValidator);
+ register.directive('uniqueTeamName', UniqueTeamNameValidator);
+ register.directive('uniqueFactoryName', UniqueFactoryNameValidator);
}
}
diff --git a/dashboard/src/components/widget/input/che-input.directive.ts b/dashboard/src/components/widget/input/che-input.directive.ts
index fe743a9e6f..49979b6f79 100644
--- a/dashboard/src/components/widget/input/che-input.directive.ts
+++ b/dashboard/src/components/widget/input/che-input.directive.ts
@@ -22,6 +22,7 @@ interface ICheInputAttrs extends ng.IAttributes {
cheReadonly: string;
cheDisabled: string;
cheWidth: string;
+ ngChange: string;
}
/**
@@ -53,13 +54,12 @@ export class CheInput implements ng.IDirective {
placeHolder: '@chePlaceHolder',
pattern: '@chePattern',
myForm: '=cheForm',
- isChanged: '&ngChange',
+ isChanged: '&?ngChange',
readonly: '=cheReadonly',
disabled: '=cheDisabled'
};
}
-
/**
* Template for the current toolbar
* @param element {ng.IAugmentedJQuery}
@@ -85,6 +85,9 @@ export class CheInput implements ng.IDirective {
if (attrs.cheDisabled) {
template = template + ' ng-disabled="disabled"';
}
+ if (attrs.ngChange) {
+ template = template + ' ng-change="isChanged({$value: valueModel})" ';
+ }
template = template + ' ng-trim="false" ng-model="valueModel" >'
+ ''
+ ''
@@ -107,6 +110,9 @@ export class CheInput implements ng.IDirective {
if (attrs.cheDisabled) {
template = template + ' ng-disabled="disabled"';
}
+ if (attrs.ngChange) {
+ template = template + ' ng-change="isChanged({$value: valueModel})" ';
+ }
template = template + '>';
if (attrs.cheWidth === 'auto') {
template = template + '{{valueModel ? valueModel : placeHolder}}
';
@@ -191,17 +197,5 @@ export class CheInput implements ng.IDirective {
element.removeClass(desktopPristineClass);
}
});
-
- const ngChange = 'ngChange';
- if (!attrs.$attr[ngChange]) {
- return;
- }
-
- // for ngChange attribute only
- $scope.$watch(() => {
- return $scope.valueModel;
- }, () => {
- $scope.isChanged();
- });
}
}