AngularJs - Error while using index of ng-repeat in map element - angularjs

I'm trying to launch an ng-click function inside an ng-repeat but I get a problem, while clicking the element, the function always pick the last occurrence of my loop.
To be more precise here's an example:
<div ng-controller="qualityController">
<div ng-repeat="quality in qualities">
<img src ={{ asset('bundles/mybundle/img/jauge_normal.png') }} width="160" height="160" alt="Circle" usemap="#circle">
<div class="g-performance-rate-knob">
<input type="text" data-angleOffset=180 data-angleArc=360 data-fgColor="#ff7200" data-width="116" data-height="116" data-step="0.1" data-min="0" data-max="100" data-readOnly=true knob class="dial" ng-model="quality.note">
</div>
<map name="circle" id="circle" ng-click="loadQualityDetail(quality.id)">
<area shape="circle" coords="80,80,80" data-toggle="modal" data-target="#modal-stars-{[{ quality.id }]}" class="more" alt=""/>
</map>
</div>
</div>
Js:
app.controller('qualityController', function ($scope,$http)
{
qualities = [];
qualities.push({id : 1});
qualities.push({id : 2});
qualities.push({id : 3});
qualities.push({id : 4});
$scope.loadQualityDetail = function(qualityId)
{
console.log(qualityId);
}
});
Wherever I click, I get "4" in my console.
Note: I use jQuery Knob library. But it seems like the problem appear on map or area elements.
If you need more information please tell me I could make a fiddle.
Thanks by advance,

Related

Reference Angular binding from javascript

I'm looking for a (best-practice) way to iterate through a list of elements in the scope of an angular controller and generate a div with an element specific id and append a svg to the element specific div. I'm very new to Angular...and suspect that the following attempt fails because I misunderstand Angular bindings?
What is a better way to do the following:
<div id="top_level">
<div ng-repeat="item in items">
<div id={{item.id}}>
<script type="text/javascript">
var svg_img = build_svg(args);
document.getElementById({{item.id}}).appendChild(svg_img);
</script>
</div>
</div>
</div>
Thanks!
You should place your logic inside of your controller and conditionally render as much html as necessary rather than invoking a script tag inside of an ng-repeat..
<div ng-controller="YourCtrl">
<div id="top_level">
<div ng-repeat="item in items">
<div id={{item.id}}></div>
<div ng-bind-html="$scope.buildSvg(item)">
</div>
</div>
</div>
</div>
In your angular controller, you would then add a function to build out and return the svg for you to render.
app.controller('YourCtrl', ['$scope', function ($scope) {
$scope.buildSvg = function (item) {
// add logic here.
}
});
What does your function build_svg return?
We'd need a little more information about the kind of end-result you would like to get.
But yeah, it's not really good practice to have a script element within a ng-repeat directive.
I see two solutions here:
1- Build your SVG directly within the ng-repeat
<div id="top_level">
<div ng-repeat="item in items">
<div id={{item.id}}>
<svg height="{{item.svg.attrs.height}}" width="{{item.svg.attrs.width}}">
<circle cx="50" cy="50" r="40" stroke="black" stroke- width="3" fill="red" />
</svg>
</div>
</div>
</div>
Here is a plunker of this method:
http://plnkr.co/edit/g58BUPScjKHjRLAfx6ks?p=preview
2- Create a directive to generate your SVG with some additional parameters and flexibility.
<div id="top_level">
<div ng-repeat="item in items">
<div id={{item.id}}>
<my-svg attrs="item.svg.attrs"></my-svg>
</div>
</div>
</div>
The my-svg directive would generate a SVG element with the attrs parameters.

AngularJS Expression Not Working Correctly in ng-src with JSF

The angularjs module. the products array contains 2 product objects that will be added as a property of the controller.
(function () {
var app = angular.module('myApp', []);
var products = [
{
title: "Dummy Title 1",
description: "Dummy Description 1",
image: "dummy_image_1.jpg"
},
{
title: "Dummy Title 2",
description: "Dummy Description 2",
image: "dummy_image_2.jpg"
}
];
app.controller('myController', function () {
this.products = products;
});
})();
The JSF Page, if I remove images/{{product.image}} with the actual image file name such as images/dummy_image_1.jpg, the images are displayed, but if I use angularjs expression instead, then nothing is shown. Please note that other expressions in the loop work besides {{product.image}}. If I add {{product.image}} somewhere else, then it displays the filename correctly, but used in ng-srs, it prints nothing if I view the html. I don't know why it is.
<h:form>
<div class="container" ng-controller="myController as controller">
<div class="row">
<div class="col-sm-offset-10">
Hello <b><h:outputText value="#{user.userName}"/></b><br/>
<h:commandLink action="cart" value="Cart"/>
</div>
</div>
<hr/>
<div ng-repeat="product in controller.products">
<div class="row">
<div class="media">
<div class="media-left">
<img class="media-object" ng-src="images/{{product.image}}"/> <!--If I replace that expression with a the image file name, it shows the image -->
</div>
<div class="media-body">
<h4 class="media-heading">{{product.title}}</h4>
<span class="caption">{{product.description}}</span><br/>
<h:commandLink action="cart" value="Add to cart"/>
</div>
</div>
</div>
</div>
</div>
</h:form>
Sometimes using interpolation {{}} won't evaluate & update value of attribute (most often this happens in IE). The way to do this is using ng-src directive with interpolation {{}} this will add src to the img tag after evaluation interpolation directive.
Markup
<div class="media-left">
<img class="media-object" ng-src="{{'images/'+product.image}}"/>
<!--If I replace that expression with a the image file name, it shows the image -->
</div>
Alternative
The other way would be using ng-attr directive which add attribute with evaluated value. This will ensure you everytime that the interpolated value has been assigned to the attribute mentioned it in ng-attr (the part after ng-attr is considered as attribute to be added, suppose we have ng-attr-value="{{someVar}}" then angular will evaluate someVar and then assign that value to value attribute on that element.
Markup
<div class="media-left">
<img class="media-object" ng-attr-src="{{'images/'+product.image}}"/>
<!--If I replace that expression with a the image file name, it shows the image -->
</div>

Firebase makes me stop typing after one keystroke in my AngularFire/AngularJS project

I started using Firebase (AngularFire) for synchronizing my data for my application. It's a Card tool for Scrum that adds cards to an array. You can manipulate the input fields.
In the first place I used localStorage, which worked really well. Now that I basically implemented Firebase, I got the following problem: After typing a single key into one field, the application stops and the only way of resuming typing is to click in the input field again.
Do you know why this is? Thank you very much in advance!
That's my basic implementation in my Controller:
Card = (#color, #customer, #points, #number, #projectName, #story) ->
$scope.cards = []
reference = new Firebase("https://MYACCOUNT.firebaseio.com/list")
angularFire(reference, $scope, "cards")
$scope.reset = ->
$scope.cards = []
$scope.addCardRed = (customer) ->
$scope.cards.push new Card("red", customer)
That's my Markup:
<div class="card card-{{ card.color }}">
<header>
<input class="points" contenteditable ng-model="card.points"></input>
<input class="number" placeholder="#" contenteditable ng-model="card.number"></input>
<input class="customerName" contenteditable ng-model="card.customer.name"></input>
<input class="projectName" placeholder="Projekt" contenteditable ng-model="card.projectName"></input>
</header>
<article>
<input class="task" placeholder="Titel" contenteditable ng-model="card.task"></input>
<textarea class="story" placeholder="Story" contenteditable ng-model="card.story"></textarea>
</article>
<footer>
<div class="divisions">
<p class="division"></p>
<button ng-click="deleteCard()" class="delete">X</button>
</div>
</footer>
</div>
<div class="card card-{{ card.color }} backside">
<article>
<h2 class="requirement">Requirements</h2>
<textarea class="requirements" placeholder="Aspects" contenteditable ng-model="card.requirements"></textarea>
</article>
</div>
I ran into this as well. This is because it's recalculating the entire array. Here's how I fixed it:
Bind your input to an ng-model and also add this focus directive
<input class="list-group-item" type="text" ng-model="device.name" ng-change="update(device, $index)" ng-click="update(device, $index)" ng-repeat='device in devices' focus="{{$index == selectedDevice.index}}" />
I set the selectedDevice like this
$scope.update = function(device, index) {
$scope.selectedDevice = device
$scope.selectedDevice.index = index
}
Now create this directive.
angular.module('eio').directive("focus", function() {
return function(scope, element, attrs) {
return attrs.$observe("focus", function(newValue) {
return newValue === "true" && element[0].focus();
});
};
});
Update Sorry for the delay, had a few things to tend to.
The reason why this works is because it is constantly saving the index value of the item in the array you are currently selecting. Once focus is lost, focus is returned immediately by going to that index.
If we're talking about multiple arrays, however, you'll need to refactor the setSelected code to say which array it is.
So you'd want to change
focus="{{$index == selectedDevice.index}}"
to something like
focus="{{$index == selectedDevice.index && selectedDevice.kind == 'points'}}"
Where points is the category of the array where the code appears.
I sorted this one by downloading the most recent version of angularFire.js, seems like bower installed the on that didn't have this fix. now my contentEditable is!

Animate rows through a directive inside a ng-repeat

I'm building this application in Angular where a div table is formed by using ng-repeat through the following html:
HTML
<div ng-repeat="(key, value) in data.data.ipv4">
<div class="cellbody">{{value.descr}}</div>
<div class="cellbody">{{value.protocol}}</div>
<div class="cellbody">{{value.internip}}</div>
<div class="cellbody">{{value.internrange}}</div>
<div class="cellbody">{{value.externrange}}</div>
<div class="deletecell">
<span class="toggledelete" ng-click="deleteport($event, key, 4)">
<i class="icon-minus negativehover"></i>
</span>
<span class="toggledelete" style="display:none">
<span>PORT DELETED</span>
<span class="deletedportundo" ng-click="restoreport($event, $index, 4)">
UNDO
</span>
</span>
</div>
</div>
The last div of each row, has a visible clickable button which sends a delete order to the server via the deleteport() function, and then, if everything goes all right, starts an animation where the whole cell is hidden and the previously hidden span with class 'deletedportundo' shows up.
Anyway the thing is my controller looks like this:
Angular Javascript Controller
$scope.deleteport = function(e,f) {
postData.index = f;
$http.post('serverside/router.php', postData)
.success(function(data, status, headers, config){
if (data.status == 'ok') {
var elem = angular.element(e.target);
$(elem).parent().parent().parent().children('.cellbody').hide('fast');
$(elem).parent().parent().children('.toggledelete').toggle();
$(elem).parent().parent().parent().children('.deletecell').animate({
width: "100%"
}, 300 );
$(elem).parent().parent().parent().children('.deletecell').addClass('macdeleted');
}
});
}
Which visually works as expected, except that I am aware that I should not be manipulating the DOM in the controller; I have been unsuccessfully trying to integrate this into a directive, but because every row is independent of the others I have not been able to achieve the desired effect.
Daniel,
There is nothing wrong with manipulating DOM in the controller. However, I can suggest an easier way to do it than to navigate with those nasty parent().parent().parent().parent().parent() ... calls :) .
Just add an ng-show to the toggledelete div, than just do $scope.portDeleted = false in your controller. This also works for the .cellbody tags.
As for the .deletecell class you can use ng-class, and just do $scope.deletecell = some_value.
<div ng-class="{deletecell:deletecell}">
<span class="toggledelete" ng-click="deleteport($event, key, 4)">
<i class="icon-minus negativehover"></i>
</span>
<span class="toggledelete" style="display:none">
<span>PORT DELETED</span>
<span class="deletedportundo" ng-click="restoreport($event, $index, 4)">
UNDO
</span>
</span>
</div>
For animate, you can use ngAnimate (http://www.nganimate.org/)

Webshims placeholder is being hidden when appending dynamic content

I'm trying to put together an email list template Using Handlebars.js with requirejs and Backbone.js, the initial rendering shows up as expected - a single email input with an add icon to add more.
var EmailView = bb.View.extend({
tagName: 'ul',
className: 'emailList',
events: {
"click .addEmail" : "addEmail",
"click .deleteEmail" : "deleteEmail"
},
initialize : function () {
this.template = hb.compile(hbTemplate);
},
render : function () {
this.$el.htmlPolyfill(this.template(this.model.toJSON()));
this.updateIcons();
return this;
},
...
The addEmail handler (I've tried appendPolyfill(), appendPolyFillTo, and the current updatePolyFill(). All produce the same results. The new line item is added, but all placeholders disappear (this is true for controls outside of $el, it appears to be the whole page.)
addEmail : function(e) {
this.$el.append( this.template({}) );
this.$el.updatePolyfill();
this.updateIcons();
}
What I want is for existing controls to maintain their placeholder text and the new one added showing the placeholder text as well. What am I missing?
If it helps, template looks like this ...
<li>
<span class="requiredPrompt">*</span>
<img class="icon" alt="" src="/images/emailIcon.png" />
<input type="email" class="emailAddress" value="" placeholder="Email Address" maxlength="50" required/>
<a class="deleteEmail" href="javascript:void(0)">
<img class="icon" alt="" src="/images/delFile.png" />
</a>
<a class="addEmail" href="javascript:void(0)">
<img class="icon enabled" alt="" src="/images/addFile.png" />
<img class="icon disabled" alt="" src="/images/addFile-disabled.png" />
</a>
</li>
As a quick fix you can simply return false or preventDefault() on your click handler. Here is a modfied jsfidlle.
jQuery('.addEmail').click(function () {
jQuery('.emailList').appendPolyfill(emailItem);
return false;
});
Webshims thinks the page unloaded and clears all placeholders.

Resources