I have two controllers in my AngularJS apps. In my first Controller, I have an input/dropdown field, which value I want to use in second nested controller for each ng-Change. For example,
My Code (HTML) ::
<body ng-app="myApp" ng-controller="DropdownCtrl">
<input type="text" class="form-control" ng-model="dt" ng-change="changeDate(dt)" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="open($event)">
<i class="glyphicon glyphicon-calendar"></i>
</button>
</span>
<div class="row" ng-controller="MainCtrl">
<!-- other code -->
</div>
</body>
Now what I want to do, when ng-Change is happening, I want to use changeDate(dt) function's value in MainCtrl
In order for a parent controller to communicate with a child controller, the parent controller should use $scope.$broadcast('changedValue', dt);
This will broadcast to all children controllers the new value of dt. The childController should then listen for the change with the following code:
$scope.$on('parent-message', function (event, dt) {
//you can now use dt in the child controller to do whatever it is you wanted
});
This is especially nice when using routeProviders and ng-view
Here is a great tutorial that explains this all really well:
Related
I try to hide my form after it has been 'submitted'. I want to do it with ng-if. Clicking on the button 'See' displays the form on and off, but it does not work on the button 'Add'. What is the reason for that?
I have created a JSFiddle. Link to JSFiddle.
My Form:
<form name="userAddForm" ng-submit="something()" class="form-horizontal" role="form">
<div class="form-group">
<label class="col-md-2 control-label">Username</label>
<div class="col-md-3">
<input name="username" ng-model="user.username" class="form-control" ng-required="true" placeholder="Username" type="text" />
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">Password</label>
<div class="col-md-3">
<input name="password" ng-model="user.password" class="form-control" placeholder="Password" type="password" ng-required="true" />
</div>
</div>
<button ng-disabled="userAddForm.$invalid" type="submit" ng-click="add=!add" class="btn btn-success">
<span class="glyphicon glyphicon-ok"></span> Add
</button>
</form>
</div>
Please, don't use $parent!
Use proper prototypal inheritance.
The reason it doesn't work is because you are creating a new scope through the usage of ngIf.
It does not create an isolate scope so you don't have to worry about that.
When you pass a primitive, Javascript will "shadow" that value on the prototype of the new scope.
As such, it is no longer a direct reference to the value in your parent scope.
How do you get around that?
add a dot
That roughly translates into; use an object and bind to a property of that object. objects don't get shadowed as they are not a primitive. you get to keep the reference and it just works™.
jsfiddle
Every directive in angularjs create different level of scope.So,there is different level of scope, one at form tag and one at button inside the form which create parent and child relationship between form and button inside it.As add is,primitive variable,its changes in child is not reflected in parent scope.
So,either use $parent service or define thet add variable in following way.
$scope.objHidShow = {};
$scope.objHidShow.add= false;
I would do it by calling a controller function:
$scope.something = function() {
$scope.shown = !$scope.shown;
}
What I did is to define that function and I made your controller working for the complete form.
https://jsfiddle.net/udc2rjrn/2/
The ng-if directive creates a new scope so you need to use $parent:
<button ng-disabled="userAddForm.$invalid" type="button" ng-click="$parent.add=!$parent.add" class="btn btn-success">
Updated JSFiddle
I am new to Angular. Please, consider the following piece of code.
<form name="newEventForm">
<fieldset>
<label for="eventName">Event Name:</label>
<input id="eventName" required ng-model="event.name" type="text" placeholder="Name of your event...">
<button ng-click="saveEvent(event, newEventForm)" type="submit" class="btn btn-primary">Save</button>
<button ng-click="cancelEdit()" type="button" class="btn btn-default">Cancel</button>
</form>
My question is - why do we need to pass the event argument to the saveEvent function? Doesn't using ng-model auto generate an event.name variable through two-way binding on the Angular side? e.g.
<form name="newEventForm">
<fieldset>
<label for="eventName">Event Name:</label>
<input id="eventName" required ng-model="event.name" type="text" placeholder="Name of your event...">
<button ng-click="saveEvent( newEventForm)" type="submit" class="btn btn-primary">Save</button>
<button ng-click="cancelEdit()" type="button" class="btn btn-default">Cancel</button>
</form>
In this second version of the code, I am not explicitly injecting event as a function parameter. However, when pressing submit, this is the code for saveEvent
$scope.saveEvent = function(newEventForm)
{
alert(1);
alert(newEventForm.$valid);
if(newEventForm.$valid)
{
window.alert('event ' + event.name + ' saved!');
}
}
and event is undefined. Shouldn't it be defined? Apologies if the question is a newbie's question. Just trying to get my head around how scope items are created through ng-model, and how does two-way binding work. Thanks !
UPDATE
Doh, I should've used $scope.event. Then it works. Thanks, like I said - new to this and it only dawned to me after I asked the question :)
The view is creating the event variable under the associated scope, use $scope.event.name.
Good luck
Actually all variable or model which are specified in the html are scope variable.
Example
<div ng-controller="myController" ng-init="name='Hello World'">
{{name}}
<button ng-click="myFn(name)"> Click Me </button>
</div>
In this example, I have initiated a variable called name. It is actually a scope variable. This code will actually like
myApp.controller("myController", function($scope){
$scope.name = "Hello World";
$scope.myFn = function(param){
// here you can see that your variable name passed from html is same as your scope variable
if(param == $scope.name){
alert("Yes, two are equal !!!");
}
}
});
This two are same. You can either use html or js.
I have the following problem with angular custom directives. I have a modal dialog that gets filled with input elements. These input elements get filled using ng-repeat angular directive like this
<div ng-repeat="item in params">
<label>{{item.nombre}}{{item.valor}}</label>
<div class="input-group" ng-if="item.tipo=='DATE'">
<span class="input-group-addon"><span class="glyphicon glyphicon-calendar"></span></span>
<input type="text" name="{{item.nombre}}" class="form-control reportesFechas" ng-model="item.valor"
data-custom-datepicker data-date-format="dd/mm/yy" id="{{item.nombre}}">
</div>
</div>
data-custom-datepicker is my custom attribute. The params model gets filled via a service call to a java backend like this
appbsReportsParamsService.query({
q: "idReport="+id
}, function(data){
$scope.params = data.content;
})
The service call works OK because the final HTML is "correct" in terms of inputs gets generated. However data-custom-datepicker doesn't get applied.
This is the HTML "ng-repeat" portion being generated:
<div class="input-group ng-scope" ng-if="item.tipo=='DATE'">
<span class="input-group-addon"><span class="glyphicon glyphicon-calendar"></span></span>
<input type="text" name="fecDesde" class="form-control reportesFechas hasDatepicker ng-pristine ng-valid ng-touched" ng-model="item.valor" data-custom-datepicker="" data-date-format="dd/mm/yy" id="fecDesde">
</div>
<div class="input-group ng-scope" ng-if="item.tipo=='DATE'">
<span class="input-group-addon"><span class="glyphicon glyphicon-calendar"></span></span>
<input type="text" name="fecHasta" class="form-control reportesFechas hasDatepicker ng-pristine ng-valid ng-touched" ng-model="item.valor" data-custom-datepicker="" data-date-format="dd/mm/yy" id="fecHasta">
</div>
So basically I want to know how to apply the directive after a async service call to populate the model.
Try adding $scope.$apply() in your service success call after $scope.params = data.content.
Because your params service query is running outside of the $scope in Angular, doing the $apply, will force update the $scope.
See if that helps.
appbsReportsParamsService.query({
q: "idReport="+id
}, function(data){
$scope.params = data.content;
$scope.$apply();
});
Ok, the problem was I was running the directive code under "compile" phase. I change it to "post" phase, now everything works ok. The problem is the Angular workflow (not the problem, but where my misconception was). This post helped me understand.
Angular directives - when and how to use compile, controller, pre-link and post-link
I am trying to create custom elements which will convert my form elements to match bootstrap's form styling structure
Basically,
<my-input ng-model="myname">
should become
<div class="form-element">
<input ng-model="myname" />
</div>
The problem is that when I use transclude, the ng-model goes to the root element and the resulting DOM is
<div class="form-element" ng-model="myname">
<input>
</div>
Is it possible to choose which inner element the ng-model attribute is transferred to??
If I create another directive called my-model and use it instead of ng-model, how can I transfer this to the inner input element?
<my-input my-model="myname">
should become
<div class="form-element">
<input ng-model="myname" />
</div>
I think it is unnecessary to use ng-transclude here, you can simply have directive
<my-input model="myname">
and directive template
<div class="form-element">
<input ng-model="model" />
</div>
where directives scope is
scope: {
'model': '='
}
By using this you can have couple of models in directive and you can put them wherever you want.
Yes. I ran into this issue a little while ago.
You need to bind your ng-model as a property of an object such as.
<div class="form-element">
<input ng-model="user.myname" />
</div>
And in controller, make sure you do this.
$scope.user = {};
In this way, angular would be able to find the ng-model.
I am using AngularJS 1.2.12 and angular-strap 2.0.0-rc.2 (mgcrea.github.io/angular-strap/) and I can't find a way to open the datepicker/timepicker widget from within the controller. I want to use an input-group with a calendar-icon-button like this:
<div class="input-group">
<input class="form-control" ng-model="searchRequest.from_created" data-autoclose="1" bs-datepicker type="text">
<span class="input-group-btn">
<button type="button" class="btn btn-default">
<i class="glyphicon glyphicon-calendar"></i></button>
</span>
</div>
I now could easily provide an ng-click function for the button and open the calendar from my controller. I just can't find a way how to do this. Any ideas?
Another solution is to change the button to a label, and use the 'for' attribute. I like it because it eliminates extra javascript to open the datepicker, and also when tabbing the cursor won't stop on the icon anymore.
<div class="input-group">
<input id="createdDate" name="createdDate" class="form-control" ng-model="searchRequest.from_created" data-autoclose="1" bs-datepicker type="text">
<span class="input-group-btn">
<label class="btn btn-default" for="createdDate">
<i class="glyphicon glyphicon-calendar"></i></label>
</span>
</div>
The documentation talks about opening the datepicker programmatically, but it doesn't give an easy way to get a reference to a datepicker that's already bound to an element.
In a project I'm working on I have a datepicker directive that wraps almost exactly the HTML you have into a myDatepicker directive. Inside that directive the ng-click method bound to the <button> element is essentially:
scope.openDatepicker = function() {
element.children('input').focus();
}
which worked well enough for me.
Since angular-strap has been rewritten to get rid of any bootstrap.js dependencies a lot of bugs and oddities have been introduced. I'm working on upgrading my project's codebase to the newer version of angular-strap, and I feel like going with UI Bootstrap would have been a better choice, since its codebase is a bit more mature.