Access ng-model created via an isolate scope in Angular - javascript

I have a simple directive using isolate scope which passes data to a scoped method from within the template:
app.directive("phone", function () {
return {
scope: {
dial: "&"
},
template: '<input type="text" ng-model="value">' +
'<br>' +
'<div class="button" ng-click="dial({message:value})">' +
'Call home!</div>',
controller: function($scope) {
console.log($scope);
}
};
});
Works fine. But I'd like to clear the input field after the alert has been completed. I'm having a hard time figuring out how I can access ng-model="value" on that input that is generated from within the directive. Any help?
Here's a plunk for you

change the template to this
template: '<input type="text" ng-model="value">' +
'<br>' +
'<div class="button" ng-click="dial({message:value}); value = \'\' ">' +
'Call home!</div>',
note that ng-click is changed to ng-click="dial({message:value}); value = \'\' "
this will sets the value to empty string after calling the dial() function.
here is the demo
or you can try something this, but seems like first one is the better one.

Related

add traduction to ui-datepicker in angular ui-grid

is there a way to translate the button in the angular ui-datepicker in this plunker example.
I tried adding close-text="{{\'lblClose\' | translate}}" current-text="{{\'lblToday\' | translate}}" clear-text="{{\'lblClear\' | translate}}" like the other Angular ui-datepicker but it's not working.
any help is really apreciated
you can do it just by updating the directive like this <div class="datepicker-wrapper" ><input uib-datepicker-popup is-open="isOpen" ng-model="' + attrs.rowField + '" ng-change="changeDate($event)" close-text="closeText" current-text="curentText" clear-text="clearText"on-open-focus="false" disabled/></div>
Please see this plunker for result
After looking more deeply on how ui-grid-datepicker is working I found a dirty solution (I don't think there is a clean solution)
You can see a plunker here where I changed the text of the close button:
http://plnkr.co/edit/za99R9wUOcM2s2EkHLsv?p=preview
THe problem is that the setting to change the Done button must be applied on the element that has the directive "uib-datepicker-popup"
So if you want to modify the label of the Done button you have to change the library of ui-grid-settings (which is not a good solution but I don't see any other way).
from this:
template: function(element, attrs) {
var html = '<div class="datepicker-wrapper" ><input uib-datepicker-popup is-open="isOpen" ng-model="' + attrs.rowField + '" ng-change="changeDate($event)" on-open-focus="false" disabled/></div>';
return html;
},
You change it to (notice I added the close-text attribute with a paramter) :
template: function(element, attrs) {
var html = '<div class="datepicker-wrapper" ><input uib-datepicker-popup is-open="isOpen" close-text="' + attrs.closeLabel + '" ng-model="' + attrs.rowField + '" ng-change="changeDate($event)" on-open-focus="false" disabled/></div>';
return html;
},
And then in your main file app.js, from this:
editableCellTemplate: '<div><form name="inputForm"><div ui-grid-edit-datepicker row-field="MODEL_COL_FIELD" ng-class="\'colt\' + col.uid"></div></form></div>'
you change it to :
editableCellTemplate: '<div><form name="inputForm"><div ui-grid-edit-datepicker close-label="' + closeLabelTranslated + '" row-field="MODEL_COL_FIELD" ng-class="\'colt\' + col.uid"></div></form></div>'
The only thing remaining is to set your variable closeLabelTranslated to whatever you want, for instance using angular-translate module (I didn't add this to the plunker):
var closeLabelTranslated = $filter('translate')('DONE');
Like I said this is dirty solution but it seems ui-grid-edit-datepicker doesn't provide you with this option so you have to add it manually

angular ng-click event not firing

I have a function that adds certain html to my page when called :
function htmlAppend(i)
{
dynamicHtml = dynamicHtml + '<div id="list_item_wrapper">' +
'<div class="list_item_template" id="list_image_wrapper">' +
'<img class="list_image_style" ' +
'src=" ' + jsonData.cars[i].ImgURL + ' "/>' +
'</div>' +
'<div class="list_item_template white_font car_details_wrapper">' +
jsonData.cars[i].CarName+ '<br>' +
jsonData.cars[i].Brand + '<br>' +
jsonData.cars[i].Model + '<br>' +
jsonData.cars[i].FuelType + '<br>' +
'<span style="font-size:40px;">' +
'₹ ' + jsonData.cars[i].Price +
'</span> <br> ' +
jsonData.cars[i].Experience +
'<input type="button" id="buy_now_btn" class="button1" ng-click="alert("hi")">Buy</button>' +
'</div>' +
'</div>'
}
Problem : Now this html is displayed correctly in my page but for some reason when button is clicked ng-click event doesn't fire , when i replaced it with onClick then onClick fires . i am unable to understand why ng-click is not firing , can somebody help ?
Additional Info : htmlAppend is a private function of a service that is called from the controller upon some user input.
No, you can't just write alert on your ng-click. When you write alert("hi") on your ng-click directive, it automatically goes and look for a method in your controller that is named $scope.alert(). That is why onClick works, because it is just plain old JavaScript, where as ng-click involves scope binding.
In your controller, write this:
$scope.alert=function(string){
alert(string);
};
and you are good to go. Here is the working plnkr.
Edit: did not read carefully that you are dynamically binding it. Updated plnkr.
For this case you will need to compile it:
var $el = $('<button ng-click=' + 'alert("hello")' + '>I am a button</button>');
$compile($el)($scope).appendTo('#testing');
where #testing can be any DOM selector you want.
Still the point is to tell you you can't just write alert in ng-click directive.
Added bonus: do not write DOM manipulating logic inside the controller. You may want to use a directive instead.

Creating names for elements created by an Angular directive

For a project I'm working on, I created a simplified version of the UI Bootstrap Calendar widget.
Plunker of my Simplified Calendar, and how I'm using it, is here.
One interesting aspect of the UI Bootstrap calendar, is that even though it goes onto a input[text], it still produces a date validation in the $error dictionary for a form controller, just as if I had specified an input[date] element in my DOM.
However, there's a catch with numerous sub-catches. One thing you'll notice right away in my plunker's DOM is that I've specified error spans for times when the given date fields are not actually dates (try entering something ridiculous like 'cat' for a value!) If you enter something that isn't a date, those should appear, but they don't.
I've tried a few things to expose the markup being created to the name field of the parent:
$transclude set to false, such that the <calendar></calendar> tags get replaced with the contents of the calendar directive's template, with a name attribute specified. This "works", except that said input is wrapped in a span that has a class necessary to look correct using the Bootstrap styling framework.
Directly creating a name attribute in the calendar directive's input field with a binding, like so*:
app.directive('mustPrecedeDate', [
function () {
return {
restrict: 'E',
template: '<input type="text" name="{{ someName }}" />',
scope: {},
controller: 'calendarCtrl',
link: function () {}
};
}
};
Writing link code to explicitly find the input that is a child of the calendar generated markup, and assign it a name attribute. Both 2 and 3 failed, because apparently that's not really something that can be done (I can't find the SO question that was the source of that discovery.)
This leads to my Question: in what way can I get a name down to the input element, such that validation results can be reported to the $error dictionary, so that I can give my users helpful validation messages?
*: Apparently, code blocks with the 'four spaces from the left' formatting don't behave well with numbered lists, so I had to use back-quote code notation to get the text to format halfway correctly. Please feel free to correct my formatting, if I haven't found a bug in the markdown setup SO uses.
The #3 thing needed to be tried a bit harder!
I was able to get a name on the input by adding the following code into my link function:
var inputElement = elem.find('input');
inputElement.attr('name', inputName);
...Where inputName is scraped from the attributes list. I was able to get the inputName down to the generated input[text] field by using a compile function as below.
app.directive('calendar', [
function() {
return {
restrict: 'E',
transclude: false,
scope: {},
template:
'<span class="input-group">'
+ '<input class="form-control" required '
+ 'type="text" placeholder="MM/dd/yyyy" '
+ 'data-ng-model="dt" data-ng-click="toggle($event)" '
+ 'data-ng-change="updateParentProperty()" '
+ 'datepicker-popup="MM/dd/yyyy" is-open="isOpen" />'
+ '<span class="input-group-btn">'
+ '<button type="button" class="btn btn-default" data-ng-click="toggle($event)">'
+ '<i class="fa fa-calendar"></i>'
+ '</button>'
+ '</span>'
+ '</span>',
controller: 'calendarCtrl',
compile: function(elem, attrs) {
var inputName = attrs.inputName;
var inputElement = elem.find('input');
inputElement.attr('name', inputName);
// Compile returns a Link function!
return function(scope, elem, attrs, ctrl) {
var modelName = attrs.ngModel;
scope.parentProperty = modelName;
scope.dt = scope.$parent[modelName];
};
}
};
}
]);

AngularJS generate HTML template with ng-click="function(arg)"

I am trying to generate an HTML templaye from AngularJS directive but I'm not able to pass any object into a function within one of the generated elements. This is my directive:
app.directive('listObject', function($compile){
return {
scope : {
obj : "="
},
controller: "httpPostController",
link : function(scope, element) {
scope.elementTree = null;
//recursivly generate the object output
scope.printObject = function (field, content) {
if (field){
content = "<div>"
if (field.isRequired){
content += "<p>" + field.name + "*:</p>";
} else {
content += "<p>" + field.name + ":</p>";
}
if (field.isEnum){
content += '<select ng-model="createEntityResource[field.name]" ng-change="getCreateEntityAsText()" class="form-control">' +
'<option></option>' +
'<option ng-repeat="enumValue in field.enumValues" label={{enumValue.name}}>{{enumValue.ordinal}}</option>' +
'</select>';
} else if (field.restResourceName) {
content += '<button type="button" ng-click="loadResourceFieldsForField(field)">Create new</button>';
// content += "<p>"+i+""+scope.printObject(field)+"</p>";
} else {
content += '<input type="text" ng-model="createEntityResource[' + field.name + ']" ng-change="getCreateEntityAsText()"' +
'class="form-control" placeholder="{{parseClassName(field.type)}}">';
}
content+="</div>";
return content;
}
};
scope.refresh = function (){
if(scope.elementTree){
scope.elementTree.remove();
}
//generate the html into a string
var content = scope.printObject(scope.obj, content);
//make elements out of a string
scope.elementTree = angular.element(content);
compiled = $compile(scope.elementTree);
element.append(scope.elementTree);
compiled(scope);
};
scope.refresh();
}
};
});
When I create a <button> element - I give it a ng-click function. The function is called and works fine, except that the param it is passed (field) is always undefined.
Does anyone know how to pass object into function within an AngularJS directive?
Every useful answer is highly appreciated and evaluated.
Thank you.
P.S. I tried to split the definition of the button to :
'<button type="button" ng-click="loadResourceFieldsForField(' + field + ')">Create new</button>';
but this does not seem work, AngularJS argues about [Object object] being passed to a function.
P.P.S I also tried to make it according to documentation which says:
Often it's desirable to pass data from the isolated scope via an
expression and to the parent scope, this can be done by passing a map
of local variable names and values into the expression wrapper fn. For
example, if the expression is increment(amount) then we can specify
Blockquote
the amount value by calling the localFn as localFn({amount: 22}).
So it looks like this, but field is still undefined:
'<button type="button" ng-click="loadResourceFieldsForField({field: field})">Create new</button>';
So my printObject algorithm worked great :)
`<button type="button" ng-click="loadResourceFieldsForField(' + field + ')">Create new</button>`
The problem here is: You are generating a string.
And you print your object into the string. This will call toString within the object and won't do what you want to do. It will just print "loadResourceFieldsForField([Object])"
`<button type="button" ng-click="loadResourceFieldsForField({field: field})">Create new</button>`
The field property in the string doesn't have any reference to your param field in the method.
Within $compile: angularjs will search for a variable field within the scope and won't find any.
You have to place this field in the scope, to make this work as aspected. But it seems not like a easy job there.
I would try this:
$compile in each printObject with an own $scope.$new containing the field variable.

Angularjs Directive

This is my scenario. I am adding a block of code dynamically using javascript. Since its dynamic I have to bind it to my angularjs scope, which is done. But I have one problem here. One of the text box has a directive for it which works. But on change of any text box other than the directive text box for first time the scope.$watch triggers, later on it does not. Here is my code
$('.addNew').click(function(){
var uniqid = Date.now();
var html= '';
html += '<section class="newItem" id="'+uniqid+'">';
html += '<h4 style="margin: 10px 22px 8px 22px;color:#FF9900;border-bottom:1px dotted black;padding:1%;" > Grocery: <em>{{gName}}</em></h4>';
html += '<div class="grosinput" style="width:0%;">-</div>';
html += '<div class="grosinput" style="width:50%;">';
html += '<lable style="color:#6699CC;font-size: 15px;">Name:</lable><input type="text" placeholder="Enter grocery item" name="name" ng-model="gName"/>';
html += '</div>';
html += '<div class="grosinput">';
html += '<lable style="color:#6699CC;font-size: 15px;">Cost:</lable><input type="text" placeholder="Enter Cost" value="30" name="cost" cost-check ng-model="cost"/></div></section>';
var $injector = angular.injector(['ng', 'grocery']);
$injector.invoke(function($rootScope, $compile) {alert('t');
$('.grocadd').hide().after($compile(html)($rootScope)).fadeIn(1500);
});
});
Here is the directive
app.directive('costCheck',function($compile,$rootScope){
$rootScope.gName= "What did i buy?";
return{
restrict: 'A',
link: function(scope,element,attrs){
scope.$watch('cost',function(oldval,newval){alert(attrs.name);
if(attrs.name === 'cost'){
alert(oldval+'--'+newval);
}
});
}
}
});
why is it triggering for other text box also
Please note Angular relies on dirty checking which means it triggers all the watches to check if anything is dirty in order to update the View.
Either you should put a if condition to check newVal and oldVal are different to go ahead as:
scope.$watch('cost',function(newVal, oldVal){
if (newVal !== oldVal){
alert(oldval+'--'+newval);
}
});
Or you can use attrs.$observe to observe the attributes as:
I changed the directive in the DOM from cost-check to cost-check="{{cost}}" and replace $watch with $observe as:
attrs.$observe('costCheck', function(val) {
console.log(scope.$eval(val));
});
Demo: http://jsfiddle.net/HB7LU/3018/

Categories

Resources