I've created a simple directive in Angular which generates a scroller to display some products.
I'm having an issue with one part of the code.
<ul ng-style="{'margin-left':{{currentMargin}}+'px'}">
<li ng-repeat="tyre in tyres" ng-style="{'width':{{liWidth}}+'px'}">
<div class="imageContainer"><img src="../Images/eutl/{{tyre.image}}"/></div>
<div class="details">
<h3>{{tyre.name}}</h3>
About this tire
</div>
</li>
</ul>
and this is what it looks like in the browser once executed
<ul ng-style="{'margin-left':0+'px'}">
<!-- ngRepeat: tyre in tyres -->
<li ng-repeat="tyre in tyres" ng-style="{'width':265+'px'}" class="ng-scope" style="width: 265px;">
<div class="imageContainer"><img src="../Images/eutl/tire.jpg"></div>
<div class="details">
<h3 class="ng-binding">Fuel Efficient</h3>
About this tire
</div>
</li>
<!-- end ngRepeat: tyre in tyres --></ul>
after executing this on my page I get the scroller and the ng-style inside the "li" elements gets displayed correctly, while the ng-style for the "ul" doesn't.
I've tried multiple solutions, even trying to add the same exact ng-style from the "li" element and it just doesn't get processed and no style is added.
Can anyone help me by pointing out a mistake in my markup or a possible cause for one ng-style working on the Li elements and the other not working on the UL itself?
The other problem I'm having is that the value of the currentMargin is not updating in IE8/9 and so on.
Thanks
ng-style accepts an Angular expression that evaluates to an object. This means that if you want to use a variable inside that expression, you can use it directly (without the double-curlies):
ng-style="{width: liWidth + 'px'}"
Double-curlies are used when you want to insert a dynamic, interpolated value to an argument that accepts a string, like <img alt="{{product.name}} logo">. You then put an expression inside those brackets.
Try to do :
ng-style="{'width':liWidth+'px'}">
No curly bracket, a lot of ng directive don't like it
Related
In the following code sample why are the brackets necessary around position[0].position in the ng-click directive in the anchor element but not in the ng-show directive in the divs?
<div ng-controller="PlayersController as pl">
<section ng-init="tab = 'goalkeepers'">
<li ng-repeat="position in pl.players">
<a href ng-click="tab = {{position[0].position}}">{{position[0].position}}</a>
</li>
</section>
<div ng-repeat="position in pl.players">
<div ng-repeat='player in position' ng-show="tab === position[0].position">
<h2 ng-show='$first'>{{player.position}}</h2>
<h3>{{player.name}}</h3>
<h4>{{player.price | currency: '£': 0}} {{player.score}}</h4>
</div>
</div>
</div>
Does it have to do with setting equality versus checking for equality? Is it related to the nested ng-repeat?
When I add brackets around the equality check in ng-show in the div element I get a parse error, why?
In Angular expressions need to be within the curly-brace bindings, where as
Angular directives do not.
As we understand that ng-click is a directive you don't need to add curly-brace there.
You don't need the brackets in the ng-click attribute. Angular evals the value of the attribute so just ng-click="tab = position[0].position;"
I'm brand new to javascript/jquery, but have been going okay so far (though you'd hate to see my code), but I've hit a wall with trying to strip out style tags from some HTML I'm trying to clone.
The reason for cloning is that the CMS I'm forced to use (which I don't have access to code behind, only able to add code over the top) automatically builds a top nav, and I want to add a duplicate sticky nav once the user scrolls, but also add a couple of elements to the scrolled version.
The original HTML of the top nav looks a bit like like:
<nav id="mainNavigation" style="white-space: normal; display: block;">
<div class="index">
Participate
</div>
<div class="index" style="margin-right: 80px;">
News
</div>
<div class="index active" style="margin-left: 80px;">
<a class="active" href="/about/">About</a>
</div>
<div class="external">
Collection
</div>
<div class="index">
Contact
</div>
</nav>
I had mild success (other than those style tags I want to remove) with the following, even though it doesn't seem to make sense to me, as I expected some of the elements would be repeated (the whole < nav >…< /nav > tag should have been within the #mainNavigation clone, no?):
var originalNavItems = $('#mainNavigation').clone().html();
$("#site").prepend('
<div id="ScrollNavWrapper">
<div class="nav-wrapper show-on-scroll" id="mainNavWrapper">
<nav id="newScrolledNav" style="white-space: normal; display: block;">
<div class="index home">
Home
</div>
' + originalNavItems + '
<div class="newItem">
<a href="http://www.externalsite.com">
View on External Site
</a>
</div>
</nav>
</div>
</div>');
I've tried to use a few answers from related questions on here, but I keep getting incorrect results. Can you help me?
You can strip the style elements like so:
var el = $('#mainNavigation'); // or whatever
el.find('[style]').removeAttr('style');
You can use
var originalNavItems = $('#mainNavigation').clone().find("*").removeAttr("style");
Then you can use .append() to add that html elements
Fiddle
You can clone into an imaginary div and then fetch the mainNavigation also. You can also remove the style attributes along with that. Hope this works for you...
var temp = $('<div />').html($('#mainNavigation').clone());
temp.find('*').removeAttr('style');
originalNavItems = temp.html();
The nav is cloned but the html() function only returns the HTML for the contents and that's why it disappears. You can avoid some string manipulation by adding the cloned element directly before a target element.
$("#site").prepend('
<div id="ScrollNavWrapper">
<div class="nav-wrapper show-on-scroll" id="mainNavWrapper">
<nav id="newScrolledNav" style="white-space: normal; display: block;">
<div class="index home">
Home
</div>
<div class="newItem">
<a href="http://www.externalsite.com">
View on External Site
</a>
</div>
</nav>
</div>
</div>');
$('#mainNavigation').clone()
.find('[style]').removeAttr('style').end()
.insertBefore('#newScrolledNav .newItem');
In the previous case find('[style]') matches elements that have a style attribute.
I'm new to Stack Overflow (and js in general), so this might be really bad ettiquette, but I seem to have accidentally fixed it myself trying to debug my implementation of the first upvoted answer that #Anoop Joshi gave above. Please comment and let me know if it would have been better to just edit my question!
I decided to break the process down into separate steps – similar to #Kiran Reddy's response actually, but I hadn't got to trying his yet.
I tried:
var styledHTML = $('#mainNavigation').clone();
styledHTML.find("div[style]").removeAttr('style');
var originalNavItems = styledHTML.html();
$("#site").prepend('<div… etc.
with a console.log(styledHTML) etc under each line to check what I had at each stage – and it worked! (The code did, console.log didn't?)
I was just doing this to try and log the value of the variables at each stage, but whatever I did fixed it…
Now I need to figure out why I can't even make console.log(variable); work :-/
Try this code
$('#mainNavigation').children().removeAttr('style');
Hope this will help you.
I have an array a=[1,2,3,4,5,6].
Using ng-repeat on this array, I am creating 6 divs.
Please refer to this plunker
Is there any way to add one more div after each row. So after 3 divs I want to add one extra div.
I looked into this example. but they are creating a child div. is it possible to create a sibling div in ng-repeat
Let's try ng-repeat-start & ng-repeat-end.
<div class="example-animate-container">
<div class="square" ng-repeat-start="friend in a">
{{$index}}
</div>
<div ng-if="$index % 3 == 2" ng-repeat-end>
extra div
</div>
</div>
Please note that ng-repeat-start directive is included since angular 1.2.1.
plnkr demo
ng-repeat: repeat a series of elements of "one" parent element
<!--====repeater range=====-->
<Any ng-repeat="friend in friends">
</Any>
<!--====end of repeater range=====-->
ng-repeat-start & ng-repeat-end: using ng-repeat-start and ng-repeat-end to define the start point and end point of extended repeater range
<!--====repeater range start from here=====-->
<Any ng-repeat="friend in friends" ng-repeat-start>
{{friend.name}}
</Any><!-- ng-repeat element is not the end point of repeating range anymore-->
<!--Still in the repeater range-->
<h1>{{friend.name}}</h1>
<!--HTML tag with "ng-repeat-end" directive define the end point of range -->
<footer ng-repeat-end>
</footer>
<!--====end of repeater range=====-->
The ng-repeat-start and ng-repeat-end syntax was introduced for this exact purpose. See the documentation http://docs.angularjs.org/api/ng/directive/ngRepeat
So you'll do something like:
<div ng-init="a = [1,2,3,4,5,6]">
<div class="example-animate-container">
<div class="square" ng-repeat-start="friend in a">
{{$index}}
</div>
<div ng-repeat-end>Footer</div>
</div>
You can use a empty div as a container for your repeat. And then only render the child element's as squares (or what ever you want). This way, your extra div will be a sibling and not a child.
See my example: http://plnkr.co/edit/xnPHbwIuSQ3TOKFgrMLS?p=preview
take a look at this plunker here, could it be your solution? i don't understand really well your problem because i think it's better if instance your array in an external js file, but other than that take a look here plunker
My s3slider is working perfectly, but I cannot get it to validate. I keep getting the error message "document type does not allow element "div" here; assume missing "li" start-tag [XHTML 1.0 Transitional]" and "end tag for "li" omitted, but OMITTAG NO was specified [XHTML 1.0 Transitional]".
Lots of people use this slider, so they just all have invalid code? The problem is the <div class="clear s3sliderImage"></div> nested inside of the <ul>. If I place it outside of the ul, the last image of the silder doesn't show - just like the author points out in the link below.
See s3slider code and instructions here.
<div id="s3slider">
<ul id="s3sliderContent">
<li class="s3sliderImage">
<img src="#">
<span>Your text comes here</span>
</li>
<li class="s3sliderImage">
<img src="#">
<span>Your text comes here</span>
</li>
<div class="clear s3sliderImage"></div>
</ul>
The only valid child of a ul is an li. To get this to validate, move the clearer inside the last li, or outside the ul.
Better, set overflow: hidden on li.sliderImage and skip the clearing div altogether. In fact, removing it on the demo page doesn't seem to have any adverse effects, at least in Chrome. My guess is that it's a fix for old IE issues.
I am currently using this piece of code to render a list:
<ul ng-cloak>
<div ng-repeat="n in list">
<li>{{ n[0] }}</li>
<li class="divider"></i>
</div>
<li>Additional item</li>
</ul>
However, the <div> element is causing some very minor rendering defects on some browsers.
I would like to know is there a way to do the ng-repeat without the div container, or some alternative method to achieve the same effect.
As Andy Joslin said they were working on comment based ng-repeats but apparently there were too many browser issues. Fortunately AngularJS 1.2 adds built-in support for repeating without adding child elements with the new directives ng-repeat-start and ng-repeat-end.
Here's a little example for adding Bootstrap pagination:
<ul class="pagination">
<li>
«
</li>
<li ng-repeat-start="page in [1,2,3,4,5,6]">{{page}}</li>
<li ng-repeat-end class="divider"></li>
<li>
»
</li>
</ul>
A full working example can be found here.
John Lindquist also has a video tutorial of this over at his excellent egghead.io page.
KnockoutJS containerless binding syntax
Please bear with me a second: KnockoutJS offers an ultra-convenient option of using a containerless binding syntax for its foreach binding as discussed in Note 4 of the foreach binding documentation.
http://knockoutjs.com/documentation/foreach-binding.html
As the Knockout documentation example illustrates, you can write your binding in KnockoutJS like this:
<ul>
<li class="header">Header item</li>
<!-- ko foreach: myItems -->
<li>Item <span data-bind="text: $data"></span></li>
<!-- /ko -->
</ul>
I think it is rather unfortunate AngularJS does not offer this type of syntax.
Angular's ng-repeat-start and ng-repeat-end
In the AngularJS way to solve ng-repeat problems, the samples I come across are of the type jmagnusson posted in his (helpful) answer.
<li ng-repeat-start="page in [1,2,3,4,5]">{{page}}</li>
<li ng-repeat-end></li>
My original thought upon seeing this syntax is: really? Why is Angular forcing all this extra markup that I want nothing to do with and that is so much easier in Knockout? But then hitautodestruct's comment in jmagnusson's answer started making me wonder: what is being generated with ng-repeat-start and ng-repeat-end on separate tags?
A cleaner way to use ng-repeat-start and ng-repeat-end
Upon investigation of hitautodestruct's assertion, adding ng-repeat-end on to a separate tag is exactly what I would not want to do in most cases, because it generates utterly usesless elements: in this case, <li> items with nothing in them. Bootstrap 3's paginated list styles the list items so that it looks like you did not generate any superfluous items, but when you inspect the generated html, they are there.
Fortunately, you do not need to do much to have a cleaner solution and a shorter amount of html: just put the ng-repeat-end declaration on the same html tag that has the ng-repeat-start.
<ul class="pagination">
<li>
«
</li>
<li ng-repeat-start="page in [1,2,3,4,5]" ng-repeat-end></li>
<li>
»
</li>
</ul>
This gives 3 advantages:
less html tags to write
useless, empty tags are not generated by Angular
when the array to repeat is empty, the tag with ng-repeat won't get generated,
giving you the same advantage Knockout's containerless binding gives you in this regard
But there is still a cleaner way
After further reviewing the comments in github on this issue for Angular, https://github.com/angular/angular.js/issues/1891,
you do not need to use ng-repeat-start and ng-repeat-end to achieve the same advantages.
Instead, forking again jmagnusson's example, we can just go:
<ul class="pagination">
<li>
«
</li>
<li ng-repeat="page in [1,2,3,4,5,6]">{{page}}</li>
<li>
»
</li>
</ul>
So when to use ng-repeat-start and ng-repeat-end? As per the angular documentation, to
...repeat a series of elements instead of just one parent element...
Enough talk, show some examples!
Fair enough; this jsbin walks through five examples of what happens when you do and when you don't use ng-repeat-end on the same tag.
http://jsbin.com/eXaPibI/1/
ngRepeat may not be enough, however you can combine that with a custom directive. You could delegate the the task of adding divider items to code if you don't mind a little bit of jQuery.
<li ng-repeat="item in coll" so-add-divide="your exp here"></li>
Such a simple directive doesn't really need an attribute value but might give you lots of possiblities like conditionally adding a divider according to index, length, etc or something completely different.
I recently had the same problem in that I had to repeat an arbitrary collection of spans and images - having an element around them was not an option - there's a simple solution however, create a "null" directive:
app.directive("diNull", function() {
return {
restrict: "E",
replace: true,
template: ""
};
});
You can then use a repeat on that Element, where element.url points to the template for that element:
<di-null ng-repeat="element in elements" ng-include="element.url" ></di-null>
This will repeat any number of different templates with no container around them
Note: hmm I could've sworn blind this removed the di-null element when rendering, but checking it again it doesn't...still solved my layout issues though...curioser and curioser...
for a solution that really works
html
<remove ng-repeat-start="itemGroup in Groups" ></remove>
html stuff in here including inner repeating loops if you want
<remove ng-repeat-end></remove>
add an angular.js directive
//remove directive
(function(){
var remove = function(){
return {
restrict: "E",
replace: true,
link: function(scope, element, attrs, controller){
element.replaceWith('<!--removed element-->');
}
};
};
var module = angular.module("app" );
module.directive('remove', [remove]);
}());
for a brief explanation,
ng-repeat binds itself to the <remove> element and loops as it should, and because we have used ng-repeat-start / ng-repeat-end it loops a block of html not just an element.
then the custom remove directive places the <remove> start and finish elements with <!--removed element-->
There is a comment directive restriction, but ngRepeat doesn't support it (since it needs an element to repeat).
I think I saw the angular team say they would work on comment ng-repeats, but I'm not sure. You should open an issue for it on the repo. http://github.com/angular/angular.js
There is no Angular magic way to do this, for your case you can do this, to get valid HTML, if you are using Bootstrap. Then you will get same effect as adding the li.divider
Create a class:
span.divider {
display: block;
}
Now change your code to this:
<ul ng-cloak>
<li div ng-repeat="n in list">
{{ n[0] }}
<span class="divider"></span>
</li>
<li>Additional item</li>
</ul>