Problem Question,
I have a delete method on my cart, so when I press on delete button it delete the item of it. But my view is not getting update whereas item is getting successfully deleted.
//Cart controller
(function() {
var cartController = function($scope,cartService,NotificationService) {
getCart();
function getCart() {
cartService.getCart()
.success(function (cart) {
if (cart != null || cart != 'undefined') {
$scope.cartData = cart;
console.log(cart)
}
})
.error(function (status, data) {
console.log(status);
console.log(data);
})
};
$scope.deleteItem = function (productID) {
cartService.deleteCartItem(productID)
.success(function () {
NotificationService.add("success", "Item deleted from the cart", 3000);
getCart();
})
.error(function (status, data) {
console.log(status);
console.log(data);
})
}
cartController.$inject = ['$scope', 'cartService', 'NotificationService'];
angular.module('cartApp').controller('cartController', cartController);
}
}());
//my view
<div class="mainContainer" ng-controller="cartController">
<tr ng-repeat="cart in cartData.carts" >
<td>
<button ng-click="deleteItem(cart.id)" class="btn btn-primary">Delete</button>
</td>
</tr>
</div>
Please guide me what I am doing wrong.
Add $scope.$apply(); after the ajax call.
$scope.cartData = cart;
console.log(cart);
$scope.$apply();
When working with $scope in angular you will run into this issue when you overwrite an object on $scope (as opposed to modifying properties of that object). As previously mentioned $scope.$apply() will force Angular to reevaluate all your bindings and should cause your UI to update. That being said, making a call to your API to get the entire contents of the cart following a delete operation seems very inefficient here. You either want to send back an empty 200 OK and use that as a trigger to know that it is safe to remove the item client side using splice. The other option would be to send the new cart contents as the body of your 200 OK following a successful delete and at least save yourself an extra round trip.
Add a $scope.$apply() to the end of your call. This will run the angular digest loop and update your view.
Update the $scope.cartData array removing the deleted one on the success method
$scope.cartData.splice($scope.cartData.indexOf(productID), 1 );
Related
I am new to Angular and need your help on an issue with the ng-repeat of my app.
Issue:
I have an html page (event.html) and in the corresponding controller of the file, I make a request to a firebase collection and update an array ($scope.events). The issue is that the data from firebase takes a few seconds to load and by the time data arrives to $scope.events, ng-repeat has already been executed and it displays an empty screen. The items are displayed correctly the moment I hit on a button in the HTML page (event.html).
Sequence of events:
I have a login page (login.html) where I enter a user name and phone number and I click on the register button. I've configured this click on the register button to go to the new state (event.html).
Here is the controller code for login.html:
$scope.register = function (user) {
$scope.user = user.name;
$scope.phonenumber = user.phonenumber;
var myuser = users.child($scope.user);
myuser.set({
phone : $scope.phonenumber,
Eventid : " ",
name : $scope.user
})
var userid = myuser.key();
console.log('id is ' +userid);
$state.go('event');
}
The controller of event.html (the state: event) has the following code:
var ref = new Firebase("https://glowing-torch-9862.firebaseio.com/Users/Anson/Eventid/");
var eventref = new Firebase("https://glowing-torch-9862.firebaseio.com/Events");
var myevent = " ";
$scope.events = [];
$scope.displayEvent = function (Eventid) {
UserData.eventDescription(Eventid)
//UserData.getDesc()
$state.go('myevents');
//console.log(Eventid);
};
function listEvent(myevents) {
$scope.events.push(myevents);
console.log("pushed to array");
console.log($scope.events);
};
function updateEvents(myevents) {
EventService.getEvent(myevents);
//console.log("success");
};
ref.once('value', function (snapshot) {
snapshot.forEach(function (childSnapshot) {
$scope.id = childSnapshot.val();
angular.forEach($scope.id, function(key) {
eventref.orderByChild("Eventid").equalTo(key).on("child_added", function(snapshot) {
myevents = snapshot.val();
console.log(myevents) // testing 26 Feb
listEvent(myevents);
updateEvents(myevents);
});
});
});
});
$scope.createEvent = function () {
$state.go('list');
}
event.html contains the following code:
<ion-view view-title="Events">
<ion-nav-buttons side="primary">
<button class="button" ng-click="createEvent()">Create Event</button>
<button class="button" ng-click="showEvent()">Show Event</button>
</ion-nav-buttons>
<ion-content class="has-header padding">
<div class="list">
<ion-item align="center" >
<button class= "button button-block button-light" ng-repeat="event in events" ng-click="displayEvent(event.Eventid)"/>
{{event.Description}}
</ion-item>
</div>
</ion-content>
</ion-view>
The button showEvent is a dummy button that I added to the HTML file to test ng-repeat. I can see in the console that the data takes about 2 secs to download from firebase and if I click on the 'Show Events' button after the data is loaded, ng-repeat works as expected. It appears to me that when ng-repeat operates on the array $scope.events, the data is not retrieved from firebase and hence its empty and therefore, it does not have any data to render to the HTML file. ng-repeat works as expected when I click the dummy button ('Show Event') because a digest cycle is triggerred on that click. My apologies for this lengthy post and would be really thankful if any of you could give me a direction to overcome this issue. I've been hunting in the internet and in stackoverflow and came across a number of blogs&threads which gives me an idea of what the issue is but I am not able to make my code work.
Once you update your events array call $scope.$apply(); or execute the code that changes the events array as a callback of the $scope.$apply function
$scope.$apply(function(){
$scope.events.push(<enter_your_new_events_name>);
})
If you are working outside of controller scope, like in services, directive, or any external JS. You will need to trigger digest cycle after change in data.
You can trigger digest cycle by
$scope.$digest(); or using $scope.$apply();
I hope it will be help you.
thanks
In your case you have to delay the binding time. Use $timeout function or ng-options with debounce property in your view.
you have to set a rough time taken to get the data from the rest API call. By using any one of the methods below will resolve your issue.
Method 1:
var myapp = angular.module("myapp", []);
myapp.controller("DIController", function($scope, $timeout){
$scope.callAtTimeout = function() {
console.log("$scope.callAtTimeout - Timeout occurred");
}
$timeout( function(){ $scope.callAtTimeout(); }, 3000);
});
Method 2:
// in your view
<input type="text" name="userName"
ng-model="user.name"
ng-model-options="{ debounce: 1000 }" />
I am trying to pull content from my website through JSON. I have successfully called it and even tags are showing properly. The only issue I am facing is the list is not displaying.
Here is how my code looks like:
module.controller('FiveReasons', function($scope, $http, $rootScope, $sce) {
ons.ready(function() {
console.log("Inside 5 Reasons");
//$scope.spinner = true;
var reasonsListing = $http.get("http://vbought.com/design_14/index.php/design_ci/post/Clients");
reasonsListing.success(function(data, status, headers, config) {
console.log(data[0].post_title);
$scope.reasonsLists = data;
$scope.spinner = false;
});
reasonsListing.error(function(data, status, headers, config) {
alert("Can Not load the address Ajax");
});
});
});
I feel like list need to be refreshed after ng-repeat is completed. But I am not sure how can I do it in Angular.
Here is how I called this.
<ons-carousel swipeable overscrollable auto-scroll fullscreen var="carousel" name="FiveRes" class="FiveRes">
<ons-carousel-item style="background: #09a4c0;" ng-repeat="reasonsList in reasonsLists" bn-log-dom-creation="with">
<div class="item-label">Number</div>
</ons-carousel-item>
<ons-carousel-cover></ons-carousel-cover>
</ons-carousel>
I can't comment original posts yet so I'll just do this here. What does reasonsLists look like? Is your carousel displaying anything at all (looking at your code, it should display "Number" as many times as the length of reasonsLists)?
Otherwise, if you wanted to display, for instance, the post_title of each entries in reasonsLists instead of Number, then replace:
<div class="item-label">Number</div>
by:
<div class="item-label">{{reasonsList.post_title}}</div>
I am listing some elements and each element has a click event and as a parameter the same element.
<a class="item item-avatar item-lista" ng-click="verView({{$index}},{{view}})">
Function verView :
$scope.verView = function(index,view){
sessionService.set("view_leido",view);
$location.path("/event/view/"+index);
}
Function darLike:
$scope.darLike = function(view_id, index){
console.log(UrlService.url+'likeView/'+sessionService.get("user_id")+'/'+sessionService.get("hash")+"/"+view_id+"/");
$http({method: 'GET', url: UrlService.url+'likeView/'+sessionService.get("user_id")+'/'+sessionService.get("hash")+"/"+view_id+"/"})
.success(function(data){
if(data.status == 1){
angular.copy(data.view.TableView, $scope.views[index]);
}
})
.error(function(){
})
.finally(function(){
});
}
These elements can be given LIKE this creates a record in my database and return the number of Likes having my element, so I update my object in the list. But while sending object parameter arrives outdated, for example:
If you would LIKE to one that has 0 likes, stay at 1 like, when you click and view detail I get 0 likes yet.
Kind of 2 questions in 1 here, Finding Angular really hard to debug.
Seems like stuff just magically breaks and fixes itself.
For example I have an ajax call to delete a "site".
Worked fine, I was happy with it so I decided to add a bit of code to splice it from the list. Now my id come through as null.
I put a break point in In google chrome for my onClick() but it never gets hit.
Using MVC5 and angular
HTML
<table class="table">
<tr>
<th>
Value
</th>
<th></th>
</tr>
<tr ng-repeat="site in sites">
<td>
{{site.Value}}
</td>
<td>
<button id="delete-{{site.Id}}" class="btn btn-primary" ng-click="deleteSite(site.id)">Delete</button>
</td>
</tr>
Angular controller
ngApp.controller('siteController', ['$scope', '$http', '$location', function ($scope, $http, $location) {
$http.post(ROOT + '/Site/LoadAll/')
.success(function (result) {
$scope.sites = result;
}).
error(function (data, status, headers, config) {
// log to console?
});
$scope.deleteSite = function (id) {
//$http.post(ROOT + 'SiteList/Delete/', JSON.stringify(id)) //null id
//$http.post(ROOT + 'SiteList/Delete/', id) //Invalid JSON primitive: 5f6d794f-bf13-4480-9afd-3b10d7b6ae32.
//$http.post(ROOT + 'Site/Delete/', { id: id } )
$http.post(ROOT + '/Site/Delete/' + id)
.success(function (result) {
// log to console?
}).
error(function (data, status, headers, config) {
// log to console?
});
for (var i = $scope.sites.lenght - 1; i >= 0; i--)
{
if ($scope.sites[i].id == id)
{
$scope.sites.splice(i,1)
}
}
//for(var i=0)
// find the $scope.sites that matches the id
// javascript re mpve that elemtne from the array
};}]);
Server controller
public JsonResult Delete(Guid id)
{
try
{
//var convertedID = new Guid(id);
_siteService.Delete(id);
return Json("OK", JsonRequestBehavior.AllowGet);
}
catch (Exception e)
{
return Json("Error" + e.Message);
}
}
So can anybody spot an issue here and how do you guys debug your Angular?
It seems there is a javascript, a http request and a asp.net mvc modelbinding flow to debug here.
In javascript i would add a few console.log statements. I use chrome for development and debugging. You could add a console.log('site', i, id, $scope.sites); in your "splice loop" to check if you get the expected result.
Http traffic can be monitored with chrome in the network tab or you can download fiddler2. Both will take a little playing around with to understand but once you get it, it's pretty straightforward. Pay attention to your form values in the request. It should hold a key id with the id value of the site.
In your asp.net mvc application you can set a breakpoint on your first { line of your action method and inspect the id variable to see if that holds the expected value.
I am very new about AngularJS things. Need to do file upload with other datas in form, I found some scripts and angular plugins but I am using my own service calls $xhr. I was able to send file but i got error, bug(not real error-bug, i just named like that) or i can not use AngularJS properly. Here it is:
.
JS
var app = angular.module('ngnNews', []);
app.factory('posts', [function () {...}]); // I reduced the codes
app.factory('$xhr', function () {
var $xhr = { reqit: function (components) { ... //My Xml HTTP Request codes here }}
return $xhr;
});
app.controller('MainCtrl', ['$http','$scope','$xhr','posts',
function ($http, $scope, $xhr, posts) {
$scope.posts = posts.posts;
$scope.files = [];
var newPost = { title: 'post one', upvotes: 20, downvotes: 5 };
$scope.posts.push(newPost);
$scope.addPost = function () {
$xhr.reqit({
form: document.getElementById('postForm'),
callbacks: {
success: function (result) {
if (result.success) {
console.log($scope.posts); //[FIRST OUT]
$scope.posts.push(result.post);
$scope.title = '';
console.log($scope.posts); //[SECOND OUT]
}
}
},
values: { upvotes: 0, downvotes: 0 },
files: $scope.files
});
...
}
}]);
.
HTML
<form action="/Home/FileUp" id="postForm" method="post" enctype="multipart/form-data">
<div class="form-group input-group">
<span class="input-group-addon">Post Title</span>
<input name="title" class="form-control" type="text" data-ng-model="title" />
</div>
<ul>
<li ng-repeat="file in files">{{file.name}}</li>
</ul>
<button class="btn btn-primary" type="button" data-ng-click="addPost()">Add New</button>
</form>
SCREEN
Sample post displayed in list
.
PROBLEMS
When I click first time Add New button everything works well until $scope.posts.push(result.post);. In console, [SECOND OUT] is here:
First object has $$hashKey but second object which sent from server(added by $scope.posts.push(result.post); function) doesn't have. I want to know why is this happening? But it's not only weird thing, when I second time click Add New button, everything completed successfully (No new logs in console, adding new post to list shown screen image above).
MAIN PROPLEM
I pushed returned value from the server but post list(in screen) is not affected when first click.
QUESTIONS
- What is happening? or
- What am I doing wrong? Thanks for any explanation.
You are doing nothing wrong with respect to $$hashkey if that is your concern. When you use ng-repeat with array of objects angular by default attaches a unique key to the items which is with the property $$hashkey. This property is then used as a key to associated DOM elements with the corresponding item in the array by identity. Moving the same object in array would move the DOM element in the same way in the DOM. You can avoid this (addition of additional property on the object by angular) by using track by with ng-repeat by providing a unique key on the object or a mere $index. So with that instead of creating a unique key and attaching it to $$haskey property angular will use the unique identifier you have provided to associate the DOM element with the respective array item.
ng-repeat="post in posts track by $index"
or (id you have a unique id for each of the object in the array, say id then)
ng-repeat="post in posts track by post.id"
And since you say you are using my xml http request code here, i am assuming it is not within the angular context so you would need to manually perform the digest cycle by using $scope.$apply() is on of those ways.
$scope.addPost = function () {
$xhr.reqit({
form: document.getElementById('postForm'),
callbacks: {
success: function (result) {
if (result.success) {
$scope.posts.push(result.post);
$scope.title = '';
$scope.$apply();//<-- here
}
}
},
But ideally you could wrap your xhr implementation with a $q and if you pass $q promise from your api, you wont need to perform a manual $scope.$apply() everywhere. Because $q promise chaining will take care of digest cycle invocation.