Model's attribute not getting updated on change - javascript

I need to bind status message to variable. If it's empty I need to hide div. If it's not empty show div and message. At the moment when I update $scope.statusMessage.msgin controller the {{statusMessage.msg}} is not being updated. How to fix it?
<div class="alert alert-info"
ng-class="{'alert-danger': statusMessage.status == -1, 'alert-success': statusMessage.status == 1, 'alert-warning': statusMessage.status == 0}"
role="alert" ng-hide="(statusMessage.msg).length == 0">{{statusMessage.msg}}</div>
$scope.statusButtonAction = function(action){
$scope.statusMessage.msg = 'Validation Error';
}
UPDATE 1
<form role="form" class="form-inline" id="status-buttons">
<button type="button" class="btn btn-warning btn-lg" ng-click="statusButtonAction('Validation Error')">Validation Error</button>
</form>
UPDATE 2
declaration of :
$scope.statusMessage = {
msg: '',
status: null
};
UPDATE 3
http://jsbin.com/jaquc/2/
UPDATE 4
I use https://github.com/angular-ui/ui-router . and my config is :
prototypeApplication.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider.state('welcome', {
url: '/',
views: {
'': {
templateUrl: 'views/prototype/welcome.html',
controller: 'welcomeController'
},
'header#welcome': {
templateUrl: 'views/components/header.html'
},
'check-in#welcome': {
templateUrl: 'views/prototype/welcome/check-in.html',
controller: 'checkInController'
},
'status-buttons#welcome': {
templateUrl: 'views/prototype/welcome/status-buttons.html',
controller: 'checkInController'
}
}
})
UPDATE 5
Strange enough, but when I switch from object oriented representation to plain variables all works:
$scope.statusMessage = '123';
$scope.statusState = null;
Does it mean I have to use some trick to make AngularJS read object's property's values?

Make sure that you defined $scope.statusMessage ie:
$scope.statusMessage = {};
before you try set $scope.statusMessage.msg in your statusButtonAction function.
and use
ng-hide="!statusMessage.msg" or ng-show="statusMessage.msg"
instead
ng-hide="(statusMessage.msg).length == 0"
Please see working demo here http://jsbin.com/vavahi/1/edit

I think the issue is use of '==' instead of '==='. The former does type coercion and results are a bit 'unreliable' especially with strings/arrays... At least I use ng-hide="myArray.length === 0" as the way to control and works always as it should.
(However, I am not sure what you are trying to do in your ng-class with "... == -1" etc. - at least I don't see statusMessage.status being declared nor used in your code...)

I found that editing ui-router configuration like this solves the problem
...
check-in#welcome': {
templateUrl: 'views/prototype/welcome/check-in.html'
/*,
controller: 'checkInController' */ // should be removed to work!
...

Related

Access form from within Angular $mdDialog

I am using an Angular 1.5 Material Design $mdDialog in the recommended way, using controllerAs: "dialog". In the template I have a form: <form name="fooForm". Within the template I can access the form with no problem, e.g. ng-disabled="fooForm.$invalid || fooForm.$submitted".
But how do I access that form from within the $mdDialog controller? From what I read, I would expect to be able to do this:
const doFoo = () => {
if (this.fooForm.$dirty) {
Here this is the dialog controller.
But I get an error: TypeError: Cannot read property '$dirty' of undefined. And sure enough, if I put a breakpoint in the code, the controller has no fooForm property.
I've tried using $scope as well, but when I put a breakpoint in the code $scope has no fooForm property either.
Here's my dialog template:
<md-dialog aria-label="FooBar">
<md-toolbar>
<div class="md-toolbar-tools">
<h2>FooBar</h2>
<span flex></span>
<md-button class="md-icon-button" ng-click="dialog.cancel()">
<md-icon>close</md-icon>
</md-button>
</div>
</md-toolbar>
<form name="fooForm" ng-submit="dialog.ok()" novalidate>
<md-dialog-content>
<div layout="column" layout-padding>
<h2 class="md-headline">Foo</h2>
<div layout="row" layout-xs="column">
...
</div>
</md-dialog-content>
<md-dialog-actions>
<md-button class="md-primary" type="submit" ng-disabled="fooForm.$invalid || fooForm.$submitted">
OK
</md-button>
<md-button ng-click="dialog.cancel()">
Cancel
</md-button>
</md-dialog-actions>
</form>
</md-dialog>
How do I access a form in an $mdDialog from the dialog controller?
you need to assign the form to the Scope of the Controller. Do this by changing the form name from fooForm to dialog.fooForm.
<form name="dialog.fooForm" ng-submit="dialog.ok()" novalidate>
Scope existed and still exist disregarding controllerAs. When you use 'controllerAs xxx' that just mean - put my controller into scope and name it xxx. You can use them together:
function controller($scope) {
var vm = this;
vm.click = function() {}
$scope.click = function() {}
}
<button ng-click="xxx.click()" ...
<button ng-click="click()" ...
Now if you write ng-click="whatever();smth();"angular will use $parse(expression)(scope) to parse this expression.
Now you write form name="formName" -- angular will use $parse("formName").assign(scope, form); and put it to scope.
$parse is quite clever and can easily handle nested properties, to put form to your controller (as xxx): <form name="xxx.myForm"></form>
The form is not defined in your controller as a property and therefore you cannot access the form like if (this.fooForm.$dirty).
However you can easily pass it to your method:
const doFoo = (fooForm) => {
if (fooForm.$dirty) {
...
And in html:
ng-click="dialog.cancel(fooForm)"
Give your controller name when your $mdDialog initialize. see below code:
$scope.showDialog = function (ev) {
$mdDialog.show({
controller: 'myController',
templateUrl: 'template.html',
parent: angular.element(document.body),
targetEvent: ev,
clickOutsideToClose: false,
fullscreen: false // Only for -xs, -sm breakpoints.
})
.then(function (answer) {
$scope.status = 'You said the information was "' + answer + '".';
}, function () {
$scope.status = 'You cancelled the dialog.';
});
};
Make sure you put controller name in quotes when you create separate controller. like controller: 'myController'
if you want to pass a function then not quotes needed like controller: myController,
In html template use ng-submit="ok()" instead of ng-submit="dialog.ok()".
I have created a sample plnkr with your template and it is working fine. check here
EDIT :`
angular.module('BlankApp', ['ngMaterial']).controller('myController', function($scope, $mdDialog) {
$scope.ok = function () {
if ($scope.fooForm.$dirty) {
// do whatever you want
$mdDialog.hide("mesage");
}
};
});`

AngularJs Bind Directive parameter to mdDialog's Form

Hi guys I have a very complicated issue.
I have created a reusable directive and now i want to take the user's parameter value and bind it to my form inside the directive.
At the user's side, they are able to call the directive by:
<test-app></test-app>
Then they are able to pass in parameters into the directive :
<test-app user-email="test#hotmail.com"></test-app>
OR
<test-app user-email="{{ userEmail }} "></test-app>
//They can take value from their own controller.
At my Own side at the directive , main.js :
angular.module('TestModule').controller('MainCtrl',['$mdDialog',function($mdDialog) {
this.openDialog = openDialog;
function openDialog(){
$mdDialog.show({
controller: 'DialogCtrl as dialog',
templateUrl: 'dialog.html'
});
}
}]);
angular.module('TestModule').directive('testApp',function(){
return {
controller: 'MainCtrl as main',
scope: {
userEmail :'#'
},
restrict : 'E' ,
templateUrl : 'FormButton.html'
}
});
angular.module('TestModule').controller('DialogCtrl',['$mdDialog',function($mdDialog,$scope){
function submit(){
etc etc . .
}
}
At the FormButton.html:
<md-button ng-click="main.openDialog()"> </md-button>
At the dialog.html:
<md-dialog>
<form>
etc , etc
<input type="email" name="email" placeholder="Email" data-ng-model="userEmail">
etc , etc
</form>
</md-dialog>
Issue: I need to pass in the userEmail value from the user side and bind it to the form so that when the user opens the form , the value is there.
I think because of the templateUrl , the convention way of binding the model doesn't work.
What i have tried:
1) I tried ng-model to bind but the form is in another page so it was not able to read the value.
2) I wanted to pass the value from the directive to controller , I research online but found no viable solution to this problem.
can anyone Kindly Help with this solution?
Take a look at the $mdDialog api docs, especially at the locals option.
locals - {object=}: An object containing key/value pairs. The keys
will be used as names of values to inject into the controller. For
example,
this.userEmail = 'someone#neeae.com';
function openDialog(){
$mdDialog.show({
controller: 'DialogCtrl as dialog',
templateUrl: 'dialog.html',
locals: {
email: this.userEmail // `this` is the main controller (parent).
}
});
}
In the html:
<test-app user-email="{{ main.userEmail }} "></test-app>
DialogCtrl
angular.module('TestModule').controller('DialogCtrl', ['$mdDialog', '$scope', 'email', function($mdDialog, $scope, email) {
// Here you can use the user's email
this.userEmail = email;
function submit() {
//etc etc ..
}
}]);
At the dialog.html:
<md-dialog>
<form>
<!-- etc , etc-->
<input type="email" name="email" placeholder="Email" data-ng-model="dialog.userEmail">
<test-app email="test#hotmail.com"></test-app>
You are passing value in "email" variable. But you are not mapping this variable in directive scope.
Try this once.
<test-app userEmail="test#hotmail.com"></test-app>

Unable to set the value of bound property in angular component

I'm trying to implement a bound property for an angular component as explained in the component documentation and this example.
Unfortunately the values I'm assigning at the tag level or in the $onInit methods are never used. Nor is the value printed when I use it as a model value.
You can find the full code on plunker.
My binding definition:
(function(angular) {
'use strict';
function SearchResultController($scope, $element, $attrs) {
var ctrl = this;
ctrl.searchFor = 'nohting-ctor';
ctrl.$onInit = function() {
console.log('SearchResultController.$onInit: searchFor='+ctrl.searchFor);
ctrl.searchFor = 'nothing-int';
};
}
angular.module('myApp').component('searchResult', {
templateUrl: 'searchResult.html',
controller: SearchResultController,
bindings: {
searchFor: '<'
}
});
})(window.angular);
Template:
<p>SearchResult for <span ng-model="$ctrl.searchFor"</span></span></p>
How it's used:
<h1>Main Window</h1>
<search-input on-start-search="$ctrl.startSearch(value)"></search-input>
<search-result search-for="nothing-ext"></search-result>
None of the nothing-* values is evers shown.
Any ideas what's wrong?
The usage of you component is not correct. If you want to pass a string it should be quoted:
<search-result search-for="'nothing-ext'"></search-result>
Then next problem is that this line
<p>SearchResult for <span ng-model="$ctrl.searchFor"</span></span></p>
doesn't make sense, as ngModel directive is only valid for input controls. You want ngBind or simple {{ $ctrl.searchFor }}:
<p>SearchResult for <span ng-bind="$ctrl.searchFor"</span></span></p>

Populate ng model from value

I am trying to populate the ng-model from a value, but don't want it to update until it is saved. To do this I have the following code;
Controller;
var SettingsController = function (roleService) {
var ctrl = this;
ctrl.rename = function(name) {
ctrl.account.name = name;
};
roleService.role.settings().then(function (result) {
ctrl.account = result.data.account;
}, function (result) {
console.log(result);
});
};
A simple controller, it gets the current settings from a service and sets it to the ctrl.
When the rename(name) is called I update the name of the account (for now it just updates the scope but soon it will update also the back-end)
To rename your account I have the following piece of code
<input type="text" data-ng-model="account.name" />
<button type="button" data-ng-click="ctrl.rename(account.name)">
Rename
</button>
I use controler as so ctrl == SettingsController
Now I use data-ng-model="account.name" to update the name. This is done so I only update the name when the button is called. The only issue is how do I get the ctrl.account.name value to the input, without bubbling it up.
I could add $scope to my controller with $scope.account but that seems overkill to me. Isn't there a way to copy/populate a ng-model from an other value or some kind?
To get to the controller I use the angular routerProvider;
$routeProvider
.when('/settings/', {
templateUrl: '/user/template/settings/',
controller: 'SettingsController',
controllerAs: 'ctrl'
});

AngularJS ng-model in template passed to directive controller

I've got a directive with a controller, that builds a form for posting comments to an API via CommentsService
My directive looks a bit lik this:
app.directive('appComments', function( CommentService ) {
return {
restrict: 'E',
scope: {
event: '='
},
controller: function( $rootScope, $scope, $element ) {
$scope.comments = [];
$scope.comment_text = '';
// load comments if event ID has changed
$scope.$watch( 'event', function() {
if( typeof $scope.event != 'undefined' ) {
CommentService.get( $scope.event ).then(
function( comments ) {
$scope.comments = comments;
}
);
}
});
// post comment to service
$scope.postComment = function() {
if( $scope.comment_text != '' ) {
CommentService.post(
$scope.event,
$scope.comment_text,
function() {
// code to reload comments
}
);
}
};
},
templateUrl: '/partials/comments.html'
};
});
This is my comments.html for the directive
<div class="event-comments">
<p ng-if="!comments.length">
<span>This event has no comments.</span>
</p>
<div
class="event-comment"
ng-repeat="comment in comments"
>
<div class="comment-text">{{comment.text}}</div>
</div>
</div>
<div class="insert-comment-container" ng-if="!loading">
<form ng-submit="postComment()">
<textarea
ng-model="comment_text"
></textarea>
<div
ng-tap="postComment()"
>Post</div>
</div>
</div>
This is how I'm placing it in my main view:
<app-comments event="event.id"></app-comments>
My comments are loading, and the event id is getting passed, but when I try and post a comment the comment_text is blank.
I think I'm getting my scopes mixed up or something, I'm still not completely clear on directives
** update **
I've just realised if I set
$scope.comment_text = 'Initial text'
in the directive, it appears when the template renders inside the textarea, and the if statement in the postComments() function fires. But if I change the text in the textarea, and tap the post button, the contents of $scope.comment_text is still "Initial text", it seems to be a one way binding.
Since you are using form i believe it creates a new scope scope. As per documentation
If the name attribute is specified, the form controller is published
onto the current scope under this name.
Try to give your form a name. Or else try to pass the property as object property like
<textarea
ng-model="comment.comment_text">
</textarea>
Ok so by changing comment_text to comment.text it solved the problem, as recommended by this SO answer:
angular-bootstrap (tabs): data binding works only one-way
Using an object instead of a primitive just uses the same reference to the object property, instead of copying the primitive into the new scope.

Categories

Resources