I'm reviewing old classes and I try to finish the exercices I couldn't do before. This class is in Ionic1, using Angular1.
I have a directive using two parameters; the first one is an object which data are to be displayed, and the second one is a parameter to hide/show some elements in the display
Here is the view implementing the controller :
<ion-list>
<film-directive
ng-repeat="tmpMovie in myController.movieList"
movie="tmpMovie"
displayBtnAddFav="false"
></film-directive>
</ion-list>
And here is the directive construction :
const FilmDir = function(){
return {
"restrict":"E",
"scope":{
"movie" :"=",
"displayBtnAddFav" :"&"
},
"template":`
<ion-item>
<p ng-if="displayBtnAddFav">DISPLAY WHEN TRUE</p>
<p ng-if="!displayBtnAddFav">DISPLAY WHEN FALSE</p>
</ion-item>`,
"controller":function($scope){
//TODO
}
}
};
All the files are correctly referenced. My directive is displayed in the view, but the "displayBtnAddFav" value isn't interpreted correctly. The "DISPLAY WHEN TRUE" is always displayed
I tried :
calling the directive with displayBtnAddFav="false"
calling the directive with displayBtnAddFav=false
replacing the boolean value by a string ("a" or "b") and using ng-if="displayBtnAddFav==='a'"
Nothing works as intended and I seem to be out of options. Would any of you see what I'm doing wrong?
So I think the issue here is the scope binding:
Per the angular documentation: & bindings are ideal for binding callback functions to directive behaviors. (https://docs.angularjs.org/guide/directive)
Different bindings are ideal for different scenarios. Try changing it from a & to an =. This should allow for angular to interpret the boolean your trying to pass correctly.
const FilmDir = function(){
return {
"restrict":"E",
"scope":{
"movie" :"=",
"displayBtnAddFav" :"="
},
"template":`
<ion-item>
<p ng-if="displayBtnAddFav">DISPLAY WHEN TRUE</p>
<p ng-if="!displayBtnAddFav">DISPLAY WHEN FALSE</p>
</ion-item>`,
"controller":function($scope){
//TODO
}
}
};
Thanks a lot Kyle for your input.
After some more tests, it appears you're right despite what the doc was telling me.
Another crucial point I realized it that the directive doesn't like "camelCase" arguments : I had to change the displayBtnAddFav to displaybtnaddfav for it to work properly.
Related
I'm using Angular 1.5.9
I have a big form, which I scattered through different Bootstrap Accordion.
When there is an error in the form, I want to be able to change the class of my accordions to show in which accordions the error is located.
To check for errors in a whole form, I can check
myFormName.$error
And to check errors for an element, I can simply do
myFormName.myInputName.$error
But I don't know if there is a way to do this for multiple element at once, without having to check each element individually.
My first thought was to change the name of my inputs like so:
<input name="accordion1.fieldName">
But this didn't give me the expected result: I don't have myFormName.accordion1.$error, actually, I don't even have myFormName.accordion1.fieldName, since my data is actually stored in myFormName['accordion1.fieldName'] which is pretty much useless.
Has anyone found an answer to this problem? I think I'll have to check each field, which is kinda ugly, and a mess to maintain whenever we add / remove fields...
Maybe there is a directive out there that could do that for me, but as a non-native English speaker, I can't find which key words to use for my search in this situation.
One approach is to nest with the ng-form directive:
<form name=form1>
<div ng-form=set1>
<input name=input1 />
<input name=input2 />
</div>
</form>
{{form1.set1.$error}}
You could name the fields with a prefix such as 'accordion1_' then add a controller function that will filter your fields.
ctrl.fieldGroup = function(form, fieldPrefix) {
var fieldGroup = {};
angular.forEach(form, function(value, key) {
if (key.indexOf(prefix) === 0) {
fieldGroup[key] = value;
}
});
return fieldGroup;
}
Then ctrl.fieldGroup('accordion1') will return an object with the appriopriate fields on it. You could extend the function further to add an aggregate $error property to the resulting fieldGroup object.
I am trying to modify the project ngImgCrop (https://github.com/alexk111/ngImgCrop) for allowing crop multiple images in the same page, but I do not know how many images I would need, this is created dynamically. So, I need to associate to the 'image' field of a dynamic value, and at the same time I put this variable in my scope. The problem is that this label is not evaluating the angular code.
<div class="cropArea" id="{{'person'+person.Id}}">
<img-crop image="{{'person'+person.Id}}" result-image="myCroppedImage"></img-crop>
</div>
Even when they have the same code, when the page is loaded the html code shows:
<div class="cropArea" id="person12345">
<img-crop image="{{'person'+person.Id}}" result-image="myCroppedImage"></img-crop>
</div>
In my scope since the beginning the variable $scope.person12345 is created, but It is impossible to make the binding without this part.
What can I do?
Note:
In my init() function I create all the variables:
angular.forEach(persons, function (person, index) {
$scope['person'+person.Id]='';
});
I actually can see the variable $scope.person12345 when the page is loaded. In any case why does the expression worked for the div and not for the img-crop?
Please put your expression as a function which will execute in the Controller. string(appending string) will return by a function like below.
<div class="cropArea" id="{{'person'+person.Id}}">
<img-crop image="getImagePath(person.Id)" result-image="myCroppedImage"></img-crop>
</div>
Controller like below:
$scope.getImagePath = function(id){return 'person'+id+'.png';};
Some how there is no parser available in the directive of image, that's why you need to give parsed expression via a controller.
I know from multiple blogs and some questions here in stackoverflow that in Angular 1 ng-bind has better performance than {{ }} interpolation because of the way the $digest process works.
Angular 2 has changed the way it does data-binding and I want to know if there is any test on the subject. Specifically if this
<h1 [innerText]="obj.name"></h1>
is still better than this
<h1> {{ obj.name }} </h1>
Using getTitle() method as example. checkBinding is debug mode check, can be ignored.
Attribute binding calls sanitize and el.setAttribute:
var currVal_0 = self.context.getTitle();
if (jit_checkBinding34(throwOnChange,self._expr_0,currVal_0)) {
self.renderer.setElementAttribute(self._el_0,'innerHTML',((self.viewUtils.sanitizer.sanitize(jit_SecurityContext36.HTML,currVal_0) == null)? null: self.viewUtils.sanitizer.sanitize(jit_SecurityContext36.HTML,currVal_0).toString()));
self._expr_0 = currVal_0;
}
Interpolation, calls el.textContent = value;:
var currVal_0 = jit_interpolate36(1,'',self.context.getTitle(),'');
if (jit_checkBinding34(throwOnChange,self._expr_0,currVal_0)) {
self.renderer.setText(self._text_1,currVal_0);
self._expr_0 = currVal_0;
}
The only difference is using sanitize, you can check html_sanitizer.ts source code to see that is does some complicated stuff.
Interpolation: It represents as {{}}. it may be concatenate two string ,calculate value and display value.
Property Binding: It represents as [].It is mainly used for non-concatenate string like variable.
Interpolation is a convenient alternative for property binding in many cases.
In fact, Angular 2 translates those interpolations into the corresponding property bindings before rendering the view.
In Angular 2, I think there is no technical reason to prefer one form to the other. You should be choosing the form that feels most natural for the task.
When I use the JS to append a p tag into a div,the ng-click not working.My code as follows:
$("#newsArList").append("<p ng-click=\"myNavigator.pushPage(\'article.html\', { animation : \'slide\' } )\">Go To Article</p>");`
Actually,I
console.log("<p ng-click=\"myNavigator.pushPage(\'./www/article.html\', { animation : \'slide\' } )\">1234</p>");`the result is `<p ng-click="myNavigator.pushPage('article.html', { animation : 'slide' } )">1234</p>
I just copy this one into the <div id="newsArList"></div>,and it working.
I don't know the reason for this situation. Any suggestions?
You use angular directive, so you must compile the code into the DOM:
$("#newsArList").append('<p ng-click="myNavigator.pushPage(\'article.html\', { animation : \'slide\' } )">Go To Article</p>');
ons.compile($("#newsArList")[0]);
As described here:
ons.compile function converts your custom elements based HTML to a
normal DOM structure. Most browsers does not (yet) support custom
elements by default, you need to call the function every time to make
the magic happen.
I have a HTML-Document containing moustache expressions that angular-dart evaluates very well:
</head>
<body ng-cloak>
<ctrlTextElements>
<div id="stage">outside: {{ctrlTextElements.test1('three')}}</div>
</ctrlTextElements>
I want to dynamicaly add some HTML with moustache expression like so:
CtrlTextElements.addTextElement(mousePos.x, mousePos.y);
var div = dom.querySelector('#stage');
HttpRequest.getString("../path/text.html").then((r) {
div.children.add(new Element.html(r, validator: new AllowAllValidator()));
});
The content of the added text.html looks like this:
<div>inside: (not evaluated): {{ctrlTextElements.test1('three')}}</div>
That's the result in the browser:
outside: three
inside: (not evaluated):{{ctrlTextElements.test1('three')}}
How can I reevaluate the moustache expressions inside content that has been applied after the page was loaded?
The problem is that you are mixing jQuery like logic with angular logic here : manipulating the dom 'by hand' is rarely a good solution.
The problem here is that your newly added binding has not been compiled by angularjs = it has not been indexed as a directive that should be watched for and updated when scope changes.
Either you try a more angular way, for example using ng-hide or ng-repeat directive to display your content according to the controllers $scope (or another custom directive), or you try to $compile your newly added directive ( but this is bad ) : https://docs.angularjs.org/api/ng/service/$compile .
Maybe try in your controller :
$scope.$compile( div );
Not sure of the syntax though. Maybe you would need to write
<span ng-bind="..."></span>
instead of
{{ ... }}
to make it work.
#Alexhv is right. Sorry for my previous answer. I assumed it is about Polymer. Was already time for bed.
You can find a code example in my answer to this question: setInnerHtml doesn't evaluate Mustache
The pub package bwu_angular (http://pub.dartlang.org/packages/bwu_angular) contains this code as a Decorator (Directive) named bwu-safe-html