Angularjs ng-disabled is disabling all of my buttons - javascript

I have a function that is called on a click. Once it has been clicked, I want to disable the button that was clicked. So far all I was able to do was to get ALL buttons to disable when I click just one. I tried out putting keys but I had no luck with that.
Here is my html:
<tr ng-repeat="parcel in parcels">
<td><a ng-href="http://www.local.com/orders/{{ parcel.id }}/edit/">{{ parcel.id }}</a></td>
<td>{{ parcel.tid }}</td>
<td>{{ parcel.srfn }}</td>
<td><a class="btn btn-success" ng-disabled="isDisabled" ng-click="resolve({{parcel.id}})">Resolve</a></td>
</tr>
Here is my controller:
$scope.isDisabled = false;
$scope.resolve = function(id)
{
$scope.order_id = id;
$http({
method: 'GET',
url: '/outboundsummary/' + $scope.order_id,
})
.success(function(data){
console.log(data.dp);
$window.alert("Resolved!");
$scope.isDisabled = true;
return false;
});
}

$scope.isDisabled preserves a single state of a $scope variable in your controller. Since you want to disable the state of the resolve button of each parcel in your ng-repeat, you can use the parcel object to dictate its state, additionally you can pass the parcel variable in your resolve() function to get both the state and the id. There is no need to interpolate {{}} the parcel id when passing angular expressions to ng-click callbacks.
DEMO PLUNKER
JAVASCRIPT
$scope.resolve = function(parcel) {
$http({
method: 'GET',
url: '/outboundsummary/' + parcel.id,
})
.success(function(data){
parcel.disabled = true;
});
};
HTML
<tr ng-repeat="parcel in parcels">
<td><a ng-href="http://www.local.com/orders/{{ parcel.id }}/edit/">{{ parcel.id }}</a></td>
<td>{{parcel.id}}</td>
<td>{{parcel.desc}}</td>
<td>
<a class="btn bnt-success" ng-disabled="parcel.disabled" ng-click="resolve(parcel)">Resolve</a>
</td>
</tr>
UPDATE:
As discussed in our chat discussion, you're ng-click callback should have passed parcel instead of parcel.id - ng-click="resolve(parcel)"
Furthermore, your resolve() function should look like this:
$scope.resolve = function(parcel) {
$http({
method: 'GET',
url: '/outboundsummary/' + parace.id,
})
.success(function(data){
parcel.disabled = true;
});
};

Since ng-repeat creates a new child scope for each element this one is easy i think. Try
<td><a class="btn btn-success" ng-disabled="disabled" ng-click="[resolve(parcel.id), disabled=true]">Resolve</a></td>

You can try something like this:
<a ng-disabled="isDisabled(parcel.id)" ng-click="resolve(parcel.id)">Resolve</a>
and in your controller:
var disabled = [];
$scope.isDisabled = function(id)
{
if(disabled[id] === undefined) return false;
return disabled[id];
}
$scope.resolve = function(id)
{
disabled[id] = true;
.....
}

I would try add {{parcels |json}} above or bellow table to see if problem is in ng-disable or in data you are sending to ng-repeat

Related

passing data from clicked item to controller in AngularJS

I am attempting to follow a JSFiddle, where a user can click on a <td> item, edit it, then eventually be able to save the changes.
The example uses ng-repeat and all others I have looked at do to where as I am not, I am using data passed from a resolve command in my route folder.
$stateProvider
.state('app.patents.patent', {
url: '/{patentId}',
component: 'patent',
resolve: {
patent: ['patents', '$stateParams', function(patents, $stateParams) {
return patents.find(function(patent){
return patent.id == $stateParams.patentId;
})
}]
}
})
}]);
I have attempted to use data-id (looked at How to retrieve the clicked ElementId in angularjs?), but with no success, as I assume you cannot use the same id twice and my desired functionality requires two elements that ng-show and ng-hide depending on the boolean value passed to them.
I have now got myself in a confused state, not sure which approach to take.
Question
How do I adapt my code that doesn't use ng-repeat to work with this JSFiddle? OR do you know another apporach I can take to achieve the same results?
<tr>
<th class="text-xs-right">Short Name</th>
<td>
<span data-id="123" ng-hide="$ctrl.shortTitle.editing" ng-dblclick="$ctrl.editItem(123)">{{$ctrl.patent.shortTitle}}</span>
<input type="text" data-id="123" ng-show="$ctrl.shortTitles.editing" ng-blur="$ctrl.doneEditing(123)" ng-model="$ctrl.patent.shortTitle"></input>
</td>
</tr>
angular.module('myApp').component('patent', {
templateUrl: 'p3sweb/app/components/patents/views/patent-item.htm',
controller: function() {
var vm = this;
vm.editItem = function (item) {
item.editing = true;
}
vm.doneEditing = function (item) {
item.editing = false;
};
});
As per my understanding regarding your question I have created a jsfiddle, have a look or you can create a jsfiddle with the issue you are facing for better understanding
JSFiddle
<!DOCTYPE html>
<div ng-app ng-controller="myCtrl" class="container">Double-click on the items below to edit:
<button type="button" ng-click="newItem()">Add item</button>
<table>
<tr ng-repeat="item in items">
<td>
<span ng-hide="item.editing" ng-dblclick="editItem(item)">{{item.name}}</span>
<input ng-show="item.editing" ng-model="item.name" ng-blur="doneEditing(item)" autofocus />
</td>
</tr>
</table>
</div>
You can create an array and connect each input to a specific index starting from 0 and then pass that index to your function call.
<tr>
<th class="text-xs-right">Short Name</th>
<td>
<span ng-hide="$ctrl.editing[1]" ng-dblclick="$ctrl.editItem(1)">{{$ctrl.patent.shortTitle}}</span>
<input type="text" data-id="123" ng-show="$ctrl.editing[1]" ng-blur="$ctrl.doneEditing(1)" ng-model="$ctrl.patent.shortTitle"></input>
</td>
</tr>
angular.module('myApp').component('patent', {
templateUrl: 'p3sweb/app/components/patents/views/patent-item.htm',
controller: function() {
var vm = this;
vm.editing=[];
vm.editItem = function (index) {
vm.editing[index] = true;
}
vm.doneEditing = function (index) {
vm.editing[index] = false;
};
});
Demo: http://jsfiddle.net/F7K63/381/

angularjs: how to store the function returning value in one variable . based on ng-repeat

hi i am getting the intrestedid from ng-repeat , i want to call another service and store that data in one variable dynamically , because need send seperate api for getting images.
my html is look like this
<div class="" ng-repeat="item in items" >
<div ng-init="MyPic = getMyprofile(item.interestedTo)">
<img src="{{MyPic}}">
</div>
</div>
My controller is look like this.
$scope.getMyprofile = function(IntrstdId){
appServices.profile( IntrstdId, function(response){
$scope.meDetails = response.data;
})
return $scope.meDetails;
}
My services is look like this.
service.profile= function(userId, callback) {
path = serviceUrl + '/profile/'+ userId;
$http({
method: 'GET',
url: path
}).then(function(data) {
callback(data)
}, function(data) {});
}
but its getting undefined , any issues in this code.
I tried to resolve this by creating some abstract stub, that may be helpful to you. Please review and let me know if issue still arise
HTML
<div ng-repeat ="data_ in parentData track by $index">
<ul>
<li ng-repeat="result in data_.data track by $index" ng-init="counter=increaseCounter();">
<div ng-model="counter"></div>
</ul>
</div>
Controller
// It simply store variable value in scope.counter
$scope.counter = 0;
$scope.increaseCounter = function () {
var cnt = $scope.counter++;
return cnt;
};
//Another way is to call service while update variable vaule
$scope.counter = 0;
$scope.increaseCounter = function () {
var cnt = $scope.counter++;
AppService.updateValue(cnt);
return cnt;
};
$scope.getMyprofile = function(IntrstdId){
appServices.profile( IntrstdId, function(response){
$scope.meDetails = response.data;
})
return $scope.meDetails;
}
I think issue is this function. appService.profile is asyncronize method and before complete it function return $scope.meDetails;
my suggestion is to hardcore some value like in below and see the result. if it is working then you have to change the function accordingly.
$scope.meDetails ='some value';
return $scope.meDetails;
There are several best practice issue along with the async problem.
1.Avoid using ng-init unless you want to re-run the function when you reconstruct the element, for instance ng-if. It is more so when you use ng-repeat without track by, any changes in the data source would re-trigger all ng-init in the children.
Solution: Run them when you init the controller, or as soon as $scope.items is filled.
angular.forEach($scope.items, function(item) {
appServices.profile(item).then(function(data){
item.myPic = data;
});
});
<div class="" ng-repeat="item in items" >
<img src="{{item.myPic}}">
</div>
2.The correct way to wrap a function that returns promise (which $http is) is to return the function itself. You can research more on how to pass the resolved/rejected result around.
// not needed anymore, just to showcase
$scope.getMyprofile = function(IntrstdId){
return appServices.profile( IntrstdId );
}
// same goes with the service function
service.profile= function(userId) {
path = serviceUrl + '/profile/'+ userId;
return $http({
method: 'GET',
url: path
}).then(function(response) {
return response.data;
});
}

$watch() isn't updating the $scope

I have the following controller, and when I call $scope.remove() it makes a request to the usercart, which makes a request to the api. The api returns json object which has an object with an array of cart items.
The html on the page uses an ng-repeat to loop through the items, but the page isn't updating for some reason, and I can not figure out why.
// Main controller
app.controller('Checkout', function($scope, usercart){
$scope.cart = [];
$scope.$watch(function(){
return usercart.cart;
}, function(newVal, oldVal){
if(newVal !== oldVal){
$scope.cart = newVal;
}
}, true);
$scope.remove = function(domain){
usercart.remove(domain);
};
});
This service makes a request to the api and saves the cart data.
// User cart service
app.service('usercart', function(cart){
this.remove = function(domain){
// cart is an api service to make http requests
cart.removeDomain(domain).success(function(data){
this.cart = data.cart;
});
};
});
Here is a json response example:
{
"message":"Success",
"cart":[{
"domain":"asdfsadfsadf.org",
"years":2,
"amount":9
},{
"domain":"asdsmembers.cc",
"years":2,
"amount":24.95
},{
"domain":"asdsmembers.tv",
"years":2,
"amount":39.95
}]
}
Here is the html:
<tr ng-repeat="i in cart">
<td data-th="Product">
{{i.domain}}
</td>
<td data-th="Price">${{i.amount|number:2}}</td>
<td data-th="Quantity">
<select ng-model="i.years" ng-options="y.value as y.name for y in selYears" ng-disable="isInCart(i.domain)" ng-class="{disabled: isInCart(i.domain)}" ng-change="update(i.domain, 'years', i.years)"></select>
</td>
<td class="actions" data-th="" align="center">
<button class="btn btn-default btn-sm" style="background: #333;" ng-click="remove(i.domain)"><span class="glyphicon glyphicon-remove-circle" aria-hidden="true" style="color:#fff;"></span></button>
</td>
<td data-th="Subtotal" class="text-center">${{i.years * i.amount|number:2}}</td>
</tr>
Also when the page loads the table displays fine. It is just when I run the remove function.
I haven't tried but i believe here is the problem
cart.removeDomain(domain).success(function(data){
this.cart = data.cart;
});
Since this is a pointer to the caller of the callback function you will create cart property onto your cart api service. In order to circumvent this issue you should create variable called (by convention) self and assign this to it (at the begining of the usercart service):
var self = this;
after that, change your code into this:
cart.removeDomain(domain).success(function(data){
self.cart = data.cart;
});
To get better understanding you can go through this post
Watching your local $scope for a value you change in your singleton usercart definitely wouldn't work, unless you explicitely passed in that local scope. We can simplify this by ridding the $watch and resolving a promise we can return from our service instead. This allows for generic re-use and alleviates watchers from polluting our controllers. Observe the following changes...
app.service('usercart', function(cart) {
this.remove = function(domain) {
return cart.removeDomain(domain) // return promise
};
});
app.controller('Checkout', function($scope, usercart) {
$scope.remove = function(domain) {
usercart.remove(domain).then(function(data) { // resolve promise
$scope.cart = data.cart;
});
};
});

AngularJS send updated data to php page via $http.post

I have just added the functionality to edit a table cell in my angularJS app. What I would like to do now is have the changes reflected in the database by sending the updated data to my PHP script, I'm a little stuck on how to actually resend the updated table.
My Angular Table in question:
<tr ng-repeat="c in resultValue=(data | filter:{'type':typeFilter} | filter:dateFilter | filter:proFilter | filter:cusFilter | filter:taskFilter | filter:nameFilter)">
<td class="jid" ng-hide="viewField">{{c.journal_id}}</td>
<td ng-show="modifyField"><input type="text" class="in1" ng-model="c.journal_id" /></td>
<td class="wda" ng-hide="viewField">{{c.work_date}}</td>
<td ng-show="modifyField"><input type="text" class="in1" ng-model="c.work_date" /></td>
</tr>
<button ng-hide="viewField" ng-click="modify(c)">Modify</button>
<button ng-show="modifyField" ng-click="update(c)">Update</button>
The controller thanks to a SO answer for the edit part:
journal.controller('dbCtrl', ['$scope', '$http', function ($scope, $http) {
$scope.loadData = function () {
$http.get("http://localhost/slick/journalFetch.php").success(function(data){
$scope.data = data;
}).error(function() {
$scope.data = "error in fetching data";
});
}
$scope.modify = function(c){
$scope.modifyField = true;
$scope.viewField = true;
};
$scope.update = function(c){
$scope.modifyField = false;
$scope.viewField = false;
//AM I ABLE TO RESEND THE UPDATED (c) DATA HERE TO THE DATABASE ?
$http({
method: "post",
url: "update.php",
data: {
//if so how to retrieve updated c data here?
}
});
};
$scope.loadData();
}]);
Looks like you are trying to update the entire table with a single Update button click. Your current code is trying to access c outside the tr element which makes c out of scope for the button.
Try passing data variable to the update function.

AngularJS Custom Filter in ng-repeat doesn't get pushed Objects

I have a problem with my custom filter function in angular.
This is the filter function:
.filter('itemFilter', function($rootScope) {
return function(input) {
var filtered = [];
angular.forEach(input, function(item) {
if(item.user_id === $rootScope.userData._id && item.active === true){
filtered.push(item);
}
});
//console.log(filtered);
return filtered;
}
});
The filter does what it should do, but when i want to push a new Object in the item Array, the filter does not get the new Object. The new Item is pushed in the array correctly, though.
This is where the item is pushed in the DB and in the rootScope. The function is located inside a factory and called in the controller.
Function in the factory:
var addItem = function(item){
$http.post("http://localhost:3333/items", item)
.success(function (response) {
$rootScope.items.push(item);
$log.debug(response);
})
.error(function (err){
$log.error("item was not added: "+err);
});
};
Call of the function in the controller:
$scope.itemObj = {"user_id": $rootScope.userData._id, "group_id": $rootScope.userData.group_id};
$scope.addItem = function() {
console.log($scope.itemObj);
dataFactory.addItem($scope.itemObj);
$modalInstance.close();
$scope.itemObj = {"user_id": $rootScope.userData._id, "group_id": $rootScope.userData.group_id};
};
The whole array with all items is located in the rootScope.
This is the part where I call the ng-repeat:
<tbody ng-repeat="item in items | itemFilter | filter: qry | orderBy: '-created'">
<tr popover="{{item.description}}" popover-trigger="mouseenter">
<td>{{item.amount}}</td>
<td>{{item.name}}</td>
<td>{{item.price | currency:"EUR€ "}}</td>
<td>{{item.list}}</td>
<td ng-controller="EditItemCtrl"><a class="btn btn-default" ng-click="open(item)">Edit</a></td>
<td><a class="btn btn-danger" ng-click="deleteItem(item)">Delete</a></td>
<td ng-controller="BoughtItemCtrl">
<a class="btn btn-success" ng-click="open(item)">Bought</a>
</td>
<td>
<p ng-show="!item.active">NO</p>
<p ng-show="item.active">YES</p>
</td>
</tr></tbody>
Is there any way to tell the filter, that a new item has been added to the array? After reloading the page, everything works fine, because the filter gets the whole items array.
I think i fixed the problem.
Instead of pushing the 'item' into the array I am now pushing the 'response' into it.
var addItem = function(item){
$http.post("http://localhost:3333/items", item)
.success(function (response) {
$rootScope.items.push(response);
$log.debug(response);
})
.error(function (err){
$log.error("item was not added: "+err);
});
};
The pushed response has an now '_id'-value (which is generated by the MonogDB). I am not sure if the missing id was the problem.
Maybe you have an answer for that.
Thanks anyway for the quick responses.

Categories

Resources