How use multiply ng-models in AngularJS - angularjs

I have textarea with ng-model 'wordset' and ng-change="onChange()"
<div>
<textarea ng-model="wordset" ng-change="onChange()"
class="form-control app-word-set"
placeholder="Enter Word Set" rows="4">
</textarea>
</div>
I have button which added new textarea in this div. I needed that already added textarea includes the same on change method that my first textarea i have. But it should use ng-model...
I want to use on method in my angularJS controller that gets values from every textarea by foreach like this:
$scope.wordSetTextarea = angular.element(document.getElementsByClassName('app-word-set'));
$scope.onChange = function() {
angular.forEach($scope.wordSetTextarea, function(value, key) {
console.log(value);
});
}
Is this possible?

With the AngularJS framework, multiple elements are added with the ng-repeat directive:
<div ng-repeat="item in itemArr">
<textarea ng-model="item.wordset"
ng-change="onChange(item,$index)"
name="'item' + $index"
class="form-control app-word-set"
placeholder="Enter Word Set" rows="4">
</textarea>
</div>
<button ng-click="addNewTextarea()">Add input</button>
$scope.itemArr = [{}];
$scope.addNewTextarea = function() {
$scope.itemArr.push({});
};
New AngularJS developers often do not realize that ng-repeat, ng-switch, ng-view, ng-include and ng-if all create new child scopes, so [data hiding problems] often shows up when these directives are involved ... [they] can be easily avoided by following the "best practice" of always have a '.' in your ng-models.
For more information, see
AngularJS ng-repeat Directive API Reference -
What are the nuances of scope prototypal / prototypical inheritance in AngularJS?

Related

angular.element is not working in tabset directive of angular js

I'm using tabset directive of angular js and using twitter bootstrap slider in tab,
My slidestop event is not calling but it's working well outside tab.
I know that tabset directive have its own scope , but dont know solution of following problem:-
<tabset class="tab-container">
<tab heading="tab1">
<div class="form-group">
<label>any Level</label>
<div class="input-group w-md">
<input id="slider" ui-jq="slider" ui-options="{min: 0,max: 10,step: 1,value: {{any_level}}}"
class="slider slider-horizontal form-control" type="text"
ng-model="any_level"> {{any_level}}
</div>
</div>
</tab>
</tabset>
controller code
......
angular.element("#slider").on('slideStop', function(data){
alert('asdasd');
})
problem is - alert is not coming when slider inside tab,alert is comming when slider outside tab
i am using this slider
Thanks
i have solved using ui-event directive to fire slidestop event
Html Code
<input id="slider"
ui-event="{slideStop: 'alertChange($event)'}" ui-jq="slider"
ui-options="{min: 0,max: 10,step: 1,value: {{any_level}}}"
class="slider slider-horizontal form-control" type="text" ng-model="any_level">
{{any_level}}
Controller Code
$scope.alertChange = function(data){
console.log(data.value); // i can get slider value on slidestop
}
Just don't use angular.element in an angular app.
EDIT : This isn't really working with ui-slider. Till ui-slider is work in progress i just woudn't use it.
Add this to your input :
ng-change="alertChange()"
And this to your controller :
$scope.alertChange = function(){
alert('hi');
}
What wasn't working ? In most of the case an angular.element will try to bind your even to the element too early. Your DOM "#slider" element isn't probably loaded when your try to bind.
EDIT An alternative :
First, after paying more attention i wouldn't recommend this slider at all.
This is actually a work in progress and isn't really reliable.
I made you an exemple of a html slider with binding in this plunker
You slider looks like this :
<input id="slider"
ng-model-options="{ debounce: 100 }"
min="0"
max="100"
ng-init="any_level = 0"
ng-change="alertChange()"
type="range"
ng-model="any_level">
This will update the model each time the value will not change for 100miliseconds. You need this to avoid firing too much ng-change function.
In your javascript you just need to declare your function
$scope.alertChange = function(){
console.log("I changed !");
//or anything else you want to do
}
I know this is not a solution but an alternative. It's not sexy as the other slider, but at least it works.
Hope it helped you.
The slider you are using has an example demonstrating how to do this. Take a look at box "12" on this page: http://angular-ui.github.io/ui-slider/demo/demo.html
In your controller you can add the following:
$scope.slider = {
'options': {
stop: function (event, ui) { $log.info('Slider stop'); };
}
And your HTML you must reference slider.options so your callback is fired:
<div ui-slider="slider.options"
min="0" max="50" ng-model="any_level"></div>

AngularJS: How to implement a directive that outputs its HTML?

I'd like to create an example directive that appends its inner HTML to itself. So, this:
<div example>
<label for="name">Name:</label>
<input id="name" type="text" ng-model="name">
</div>
should become this:
When inside a directive, the element already has things line class="ng-scope ng-pristine ng-valid" which shouldn't be in the outputted HTML.
How would implement such a directive?
My attempt is here
You probably don't need to transclude or use scope here, just use the compile function to grab the inner html and append it to the node:
.directive('example', function() {
return {
compile: function(ele) {
var innerHtml = ele.html();
ele.append(document.createTextNode(innerHtml));
}
};
});
Demo

ng-model not updating with radio button

I'm getting a problem with angular and I'm not understanding what the problem may be:
thats a div:
<div ng-controller="CountrySelectorController">
Selected Countryid = {{countryid}}
<div class="radio" ng-repeat="country in countries">
<input type="radio" name="countryOptions" ng-model="countryid" value={{country.countryid}} ng-checked="countryid == country.countryid" /><span style="margin-left:10px;">{{country.countryid}}.{{country.name}}</span>
</label>
</div>
</div>
thats my controller:
app.controller('CountrySelectorController', function($scope, $rootScope){
$scope.countryid = 1;
});
the problems I'm getting:
-Selected Countryid=1 appears at start . Although I'm selecting different countries, the model is not updating
ng-repeat creates its own scope, which is not what you want to bind the ng-model to. You want to bind ng-model to the controller's scope (which is the parent scope of the ng-repeat).
Use $parent to go up a level to the correct scope. Also, don't use ng-checked.
ng-model="$parent.countryid"
Demo

Manual creation of nodes and ng-model

In more attempts to DRY bootstrap and AngularJS, I'm attempting to create a form and children while maintaining the ng-model relationships. I'm getting the correct HTML output, but something isn't connecting correctly with the model relationships, and the model isn't being updated:
Vanilla HTML
<form role="form" ng-model="customer">
<div class="form-group">
<label for="name">Your Name</label>
<input id="name" class="form-control" ng-model="customer.name" />
</div>
</form>
Simplified (goal) HTML
<div abs-form ng-model="customer">
<input id="name" label="Full Name" placeholder="i.e. Joe Smith"/>
</div>
Controller
.controller('HomeCtrl', function($scope){
$scope.customer = {};
}
abs-form Directive
.directive('absForm', function($compile){
var input = $('<input />'),
label = $('<label />');
group = $('<div class="form-group"></div>'),
formElements = [];
return {
restrict : 'EA',
replace : true,
transclude : false,
scope : {
ngModel : '=',
label : "#"
},
compile : function(tElement, tAttrs){
var children = tElement.children();
var tplElement = angular.element('<form role="form" ng-model="'+ tAttrs.ngModel +'" />');
// Clear the HTML from our element
tElement.html('');
// Loop through each child in the template node and create
// a new input, cloning attributes
angular.forEach(children, function(child){
var newInput = input.clone(),
newLabel = label.clone(),
newGroup = group.clone(),
$child = $(child),
attributes = child.attributes;
// Add the "for" attribute and the label text
newLabel.attr('for', $child.attr('id'));
newLabel.text($child.attr('label'));
// Add the class to the input
newInput.addClass('form-control');
newInput.attr('ng-model', tAttrs.ngModel + "." + $child.attr('id'));
// Copy the attributes from the original node to the new one
$.each(attributes, function(index, prop){
newInput.attr(prop.name, prop.value);
})
// Store the form elements for use in link() later
formElements.push(newLabel, newInput)
// Some reason passing in the formElements botches the appending
newGroup.append([newLabel, newInput]);
// Append the group to the element
tplElement.append(newGroup)
})
//$('input', tplElement).wrap('<span>')
// finally, replace it with our tplElement
tElement.replaceWith(tplElement);
}
}
})
This is the output of the directive above, like I said, the HTML is fine (as far as I can tell), but there's no connection of the model:
<form role="form" ng-model="customer" class="ng-pristine ng-valid">
<div class="form-group">
<label for="name">Full Name</label>
<input class="form-control ng-pristine ng-valid" ng-model="customer.name" id="name" label="Full Name" placeholder="i.e. Joe Smith">
</div>
</form>
Some of the questions I've found with similar scenarios (and similar ways to solve)
Changing ngModel
Adding ngModel to input
The second question was the best scenario, but I can't seem to get my new inputs to contribute to the "customer" model. I'm thinking there's more to it than just adding or changing the ng-model attribute on the node, but something Angular is doing to register the connection...?
The problem with your directive is that it introduces an isolate scope which does not include the original model name. The scope variable customer is henceforth known by the name ngModel within the directive's scope.
I updated the code to get rid of the jQuery dependency but basically it still does the same things.
See this fiddle: manual creation of nodes and ng-model

Angular way of getting val() from a textarea

I have created a button, that when it is clicked I want to get the text from a textarea. Here is the html.
<div class="text-area-container">
<textarea id="chatBox" class="chat-box" rows="2"></textarea>
</div>
<div class="button-container btn-group btn-group-chat">
<input id="comment" ng-click="chat($event)" class="btn" value="Comment"/>
</div>
And here is my controller
$scope.chat = function($event) {
var button = $event.currentTarget;
};
I get the button from the $event, but how do I get the textarea. I know that I can jQuery it, but that is not the Angular way. How do i do it without jQuery?
Add ng-model to text area, like:
<textarea id="chatBox" class="chat-box" rows="2" ng-model="textModel"></textarea>
In controller write $scope.textModel = "";
Demo Fiddle
Angular is two way data binding. Setting ng-model will chain textarea value with controller var.
On controller side:
$scope.textArea = "";
On view side:
<textarea [...] ng-model="textArea">[...]</textarea>
On your controller, $scope.textArea will always contain textarea content.
You're looking for ng-model.
<textarea ng-model="text" id="chatBox" class="chat-box" rows="2"></textarea>
access it with $scope.text in js or {{text}} in view.
Well if you need to know only text area's value I guess it should be binded to some $scope model variable via data-ng-model="MyTextValue":
<textarea id="chatBox" data-ng-model="MyTextValue" class="chat-box" rows="2">}</textarea>
so in $scope.chat function you can get access to $scope.MyTextValue.
You can also enable/disable or show/hide control via ng-* attibutes too. In most cases it is enough.

Resources