ng-model doesnt communicate with ng-repeat - angularjs

I've been working on an app for trainers and I have encountered possibly simple
problem, despite that I dont know how to fix this and I tried many different solutions.
What i've noticed is that it works pretty fine when input is above the list generated by ng-repeat but i want the list to be under the input.
Any suggestions will be appreciated.
Here is the html code as it is now:
<html ng-app="trainingSupport">
<form method="post" enctype="multipart/form-data" action="" ng-controller="addOffer">
<div class="span40"><input type="text" ng-model="newOffers.offerName" name="offer" class='span48 offer-in'></div>
<div class="span8 options-btn">
<div class="pencil-offer"><i class="icon-pencil icon-offer"></i></div>
<button ng-click="newOffer()" type='submit' class="btn save-offer"><i class="icon-save"></i></button>
<button type="submit" class="btn trash-offer"><i class="icon-trash"></i></button>
</div>
</form>
</div>
<div class="row-fluid">
<ol class="span48" ng-controller="addOffer">
<li ng-repeat="offer in offers" ng-bind='offer.offerName' class="unbold f-pt-sans offer-list"></li>
</ol>
</html>
and here is the tha angular code:
var trainingSupport = angular.module('trainingSupport', []);
function addOffer($scope){
$scope.offers=[
{id:0, offerName:"szkolenie z pieczenia indyka"},
{id:1, offerName:"szkolenie z gaszenia wodą"},
{id:2, offerName:"szkolenia z bicia konia"}
];
$scope.newOffer = function(){
$scope.offers.push({
offerName: $scope.newOffers.offerName
});
$scope.newOffers.offerName='';
}
}
trainingSupport.controller("addOffer", addOffer);

I created a jsFiddle for this, and chiseled your code down to the basics, for better readability.
http://jsfiddle.net/yhx8h/1/
I refactored your controller quite a bit, its much cleaner now.
var trainingSupport = angular.module('trainingSupport', []);
trainingSupport.controller("addOfferCtrl",
function AddOfferCtrl($scope){
//this variable is bound to your input
$scope.newOfferName = '';
$scope.offers=[
{id:0, offerName:"szkolenie z pieczenia indyka"},
{id:1, offerName:"szkolenie z gaszenia wodą"},
{id:2, offerName:"szkolenia z bicia konia"}
];
$scope.newOffer = function(){
//handy little method to grab the max id in your array
var newId = Math.max.apply(null,$scope.offers.map(function(item){return item.id}));
//increment the id, and add new entry to the array
$scope.offers.push(
{id: newId + 1, offerName: $scope.newOfferName }
);
};
});
And the HTML:
<div ng-app="trainingSupport" ng-controller="addOfferCtrl">
<input type="text" ng-model="newOfferName" />
<button ng-click="newOffer()" type="button" text="click me to add offer" ></button>
<ol>
<li ng-repeat="offer in offers">{{offer.offerName}}</li>
</ol>
</div>
I bound your input to a separate variable, newOfferName, and got rid of the extra submit button and the <form> tag. Judging from the code you posted, I don't see why you would need to use a <form> tag in this implementation, or a submit button. Instead, you can just bind an ng-click function to a button (or almost any other type of element really) which will handle updating your array and re-binding your list. Finally, I dont see why you need an ng-bind on your <li ng-repeat>, I removed that as well. Hopefully this refactored code helps you out!

Related

Duplicated Paypal buttons with Paypal REST API and AngularJS

I'm building an Single Page App where the paypal button is generated on ng-click from a button (Add products).
The problem I'm facing, is that if the user clicks this button several times, the app will generate several buttons one after the other.
This can very well happen as the user might click the button, but then go back and add an extra product, before finish the purchase.
How could I manage to remove all existing buttons before adding the new one?
The function looks like this:
$scope.formulari = function(){
paypal.Button.render({
env: 'production', // Or 'sandbox'
locale: 'es_ES',
style: {
label: 'paypal',
...
And after a few clicks, my initial HTML button <a id="paypal-button"></a> looks like this:
<a id="paypal-button">
<div id="xcomponent-paypal-button-6d3dcbc0c4" class="paypal-button paypal-button-context-iframe paypal-button-label-paypal paypal-button-size-large paypal-button-layout-horizontal" style=""></div>
<div id="xcomponent-paypal-button-46823018c3" class="paypal-button paypal-button-context-iframe paypal-button-label-paypal paypal-button-size-large paypal-button-layout-horizontal" style=""></div>
<div id="xcomponent-paypal-button-41aad29e14" class="paypal-button paypal-button-context-iframe paypal-button-label-paypal paypal-button-size-large paypal-button-layout-horizontal" style=""></div>
<div id="xcomponent-paypal-button-48d3247535" class="paypal-button paypal-button-context-iframe paypal-button-label-paypal paypal-button-size-large paypal-button-layout-horizontal" style=""></div>
</a>
Generating a button on click might not be the way you want to go with an AngularJs structure. Editing your DOM structure is more a jQuery thing and in general you don't want to mix the two (Some explanations of why: 1, 2).
An Angular way to pick this up would be the following (Explanation beneath snippet):
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.articles = ['PC', 'Playstation', 'Xbox'];
$scope.cart = [];
$scope.addArticleToCart = function(article) {
$scope.cart.push(article);
}
$scope.clearCart = function() {
$scope.cart = [];
}
$scope.doPaypalThings = function() {
//REST API stuff
}
});
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
</head>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<div ng-repeat="article in articles">
<button ng-click="addArticleToCart(article)">
{{article}}
</button>
</div>
<br>
<div ng-show="cart.length > 0">
<button id="paypal-button" ng-click="doPaypalThings()">
Paypal
</button>
</div>
<br>
<div>
In cart:
</div>
<div ng-repeat="item in cart">
{{item}}
</div>
<br>
<div>
<button ng-click="clearCart()">
Clear cart
</button>
</div>
</div>
</body>
</html>
With this method the button always exists, it just isn't visible until the requirements within the ng-show are met. In the example, the requirement is that there are items in the cart. You will notice that once the requirements are no longer met the button will disappear again.
An opposite of ng-show is ng-hide which can be used in the same way:
ng-hide="cart.length == 0" or ng-hide="cart.length < 1
If you're dead set on using your current method, you can check out this answer here, although it is not Angular.

AngularJS- How to handle each button created by ng-repeat

I am new to AngularJS.
I have created <li> to which I used ng-repeat.
<li> contains images and buttons like like, comment and share which is inside <li> and created by ng-repeat.
I have made function which will replace empty like button to filled like button (By changing background image of button).
But problem is this trigger applies to only first like button and other buttons does not change.
How can I fix this?
Code:
HTML:
<html>
<body>
<ul>
<li ng-repeat="media in images"><div class="imgsub">
<label class="usrlabel">Username</label>
<div class="imagedb">
<input type="hidden" value="{{media.id}}">
<img ng-src="{{ media.imgurl }}" alt="Your photos"/>
</div>
<!-- <br><hr width="50%"> -->
<div class="desc">
<p>{{media.alt}}</p>
<input type="button" class="likebutton" id="likeb" ng-click="like(media.id)" ng-dblclick="dislike(media .id)"/>
<input type="button" class="commentbutton"/>
<input type="button" class="sharebutton"/>
</div>
</div> <br>
</li><br><br><br>
</ul>
</body>
</html>
JS:
$scope.like = function(imgid)
{
document.
getElementById("likeb").
style.backgroundImage = "url(src/assets/like-filled.png)";
alert(imgid);
}
$scope.dislike = function(imgid)
{
document.
getElementById("likeb").
style.backgroundImage = "url(src/assets/like-empty.png)";
}
Thanks for help & suggestions :)
The id for each button should be unique but in your case, it's the same for all buttons ('likeb').
You can set the value of the attribute 'id' for each button dynamically by using '$index' and passing '$index' to the functions as follows:
<input type="button" class="likebutton" id="{{$index}}" ng-click="like($index)" ng-dblclick="dislike($index)"/>
Then in your controller, you can use the functions with the passed value.
For example,
$scope.like = function(index)
{
document.
getElementById(index).
style.backgroundImage = "url(src/assets/like-filled.png)";
}
Another good alternative in your case would be to use the directive ngClass.
use 2 css class for styling liked and disliked state, and then put the class conditionally with ng-class instead of DOM handling. and if you really want to perform a DOM operation (I will not recommend) then you can pass $event and style $event.currentTarget in order to perform some operation on that DOM object.

Live search in AngularJS: updating the results

I want a live search: the results are queried from web api and updated as the user types.
The problem is that the list flickers and the "No results" text appears for a fraction of second, even if the list of results stays the same. I guess I need to remove and add items with special code to avoid this, calculating differences between arrays, etc.
Is there a simpler way to avoid this flicker at least, and probably to have possibility to animate the changes?
It looks like this now:
The html part is:
<div class="list-group">
<a ng-repeat="test in tests track by test.id | orderBy: '-id'" ng-href="#/test/{{test.id}}" class="list-group-item">
<h4 class="list-group-item-heading">{{test.name}}</h4>
{{test.description}}
</a>
</div>
<div ng-show="!tests.length" class="panel panel-danger">
<div class="panel-body">
No tests found.
</div>
<div class="panel-footer">Try a different search or clear the text to view new tests.</div>
</div>
And the controller:
testerControllers.controller('TestSearchListCtrl', ['$scope', 'TestSearch',
function($scope, TestSearch) {
$scope.tests = TestSearch.query();
$scope.$watch('search', function() {
$scope.tests = TestSearch.query({'q':$scope.search});
});
}]);
You should use ng-animate module to get the classes you need for smooth animation. For each ng-repeat item that's moved, added, or removed - angular will add specific classes. Then you can style those classes via CSS or JS so they don’t flicker.
An alternative way of doing what you require is to use the angular-ui bootstrap Typeahead component (check at the bottom of the post). It has a type-ahead-wait property in milliseconds and also a template url for customising it.
<div ng-app>
<div ng-controller="MyController">
<input type="search" ng-model="search" placeholder="Search...">
<button ng-click="fun()">search</button>
<ul>
<li ng-repeat="name in names">{{ name }}</li>
</ul>
<p>Tips: Try searching for <code>ann</code> or <code>lol</code>
</p>
</div>
</div>
function MyController($scope, $filter) {
$scope.names = [
'Lolita Dipietro',
'Annice Guernsey',
'Gerri Rall',
'Ginette Pinales',
'Lon Rondon',
'Jennine Marcos',
'Roxann Hooser',
'Brendon Loth',
'Ilda Bogdan',
'Jani Fan',
'Grace Soller',
'Everette Costantino',
'Andy Hume',
'Omar Davie',
'Jerrica Hillery',
'Charline Cogar',
'Melda Diorio',
'Rita Abbott',
'Setsuko Minger',
'Aretha Paige'];
$scope.fun = function () {
console.log($scope.search);
$scope.names = $filter('filter')($scope.names, $scope.search);
};
}

ng-click showing all the hidden text field on ng-repeat rather than one in Angular

I started to work with Angular, it's pretty good to implement, I stuck with a single issue at ng-click
I am getting data dynamically and showing with ng-repeat, and I want to update the data at pencil click and for it I am using input text element, but when I click on pencil It's opening all the text fields
Here is my HTML code
<
div ng-repeat="item in scroller.items track by $index">
<div class="secHead text-center">
<button class="common btnDarkGrey" data-ng-hide="hideCatButton">{{item.category_name}}</button>
<input type="text" id="focus-{{$index}}" class="common btnDarkGrey editDashboardCategory" name="editCategory" value="" data-ng-model="item.category_name" data-ng-show="hideField">
<span data-ng-click="updateCategory(item.category_id,item.category_name,$index)" class="chkOneDone" data-ng-show="hideOkButton">Done</span>
<div class="pull-right">
</div>
</div>
</div>
And here I Angular code
$scope.updateCategory=function(category_id,updated_cat_name, $index){
Category.updateCat($rootScope,$scope,$index,$http,$timeout,updated_cat_name,old_cat_name,category_id);
};
$scope.updatePen=function($index){
old_cat_name=$scope.scroller.items[$index].category_name
$scope.hideField=true;
$rootScope.hideOkButton=true;
$rootScope.hideCatButton=true;
};
I created a Category service to perform task like update
I didn't get any proper solution yet.
Can anybody help me?
Thank You.
If you only want to hide/show one of the elements in the list you need to specify that in some fashion. Right now you have a three rootScope booleans:
$scope.hideField=true;
$rootScope.hideOkButton=true;
$rootScope.hideCatButton=true;
being set for the entire list, and you need to set a show properties on each individual in the list.
In your controller function you can do something like this before you expect a click:
//normal for loop so that you have the index
for(var i=0; i < $scope.scroller.items.length; i++){
$scope.scroller.items[i].show = false;
}
Then you can do something like this to actually show the fields:
HTML:
div ng-repeat="item in scroller.items track by $index">
<div class="secHead text-center">
<button class="common btnDarkGrey" ng-hide="!item.show">
{{item.category_name}}</button>
<input type="text" id="focus-{{$index}}" class="common btnDarkGrey editDashboardCategory" name="editCategory" value="" ng-model="item.category_name" ng-hide="!item.show">
<span data-ng-click="updateCategory(item.category_id,item.category_name,$index)" class="chkOneDone" ng-show="item.show">Done</span>
<div class="pull-right">
</div>
</div>
</div>
Controller:
//controller declaration --
$scope.updatePen = function(index){
$scope.scroller.items[index].show = true;
};
It's my understanding that you need all three properties to show once a click happens, so I condensed all the show properties into one single show property.
Your view only sees that hideField is true and performs that action for all of the items in your array. I hope this helps!

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!

Resources