Cannot set option value in select programmatically using AngularJs - angularjs

The select:
select(ng-model="elId", ng-change="load(elId)", ng-options="e._id as e.name for e in options")
option(value="") - select a mashup -
Controller:
The following works, the select gets populated. I am using broadcasts because it comes from a socket.. don't mind that.
//receive list
$scope.$on('list:refresh', function(ev, data) {
$scope.options = data
})
The following only works if I did not manually select any option before. data.id is a valid entry in the list.
//refresh list of mashups when a new one has been created
$scope.$on('list:select', function (ev, data) {
$scope.elId = data.id
})
If I manually select an option, and then the list:select fires, the $scope.elId is udated but the <select> does not highlight the option.
What is going on?

Solved:
The select:
select(ng-model="data.elId", ng-change="load()", ng-options="e._id as e.name for e in options")
option(value="") - select a mashup -
Controller:
//receive list
$scope.$on('list:refresh', function(ev, data) {
$scope.options = data
})
$scope.load() {
var elId = $scope.data.elId
....
}
//refresh list of mashups when a new one has been created
$scope.$on('list:select', function (ev, data) {
$scope.data.elId = data.id
})
I guess the problem was that I tried to change the selected value from a child controller.. now I am using a service Data that I load into the controllers $scope.data = Data.. meh?

Related

Trying to replace each record having a button in AngularJS with only one button for records that are selected

So I'm working on an app that has a table listing records that have been added to a database. As it currently stands, line in the table has a record entry with one edit and one delete button for each record. So as you scroll, lots of lines, lots of delete and edit and delete buttons. I'd like to keep the table as is and get rid of the all the buttons, instead having only 2 total buttons outside of the table at the bottom of the page where you would highlight the table entry in some way and the buttons would correspond to the actions. This is all done in the controller, but I'm reworking someone else's stuff, so it's a bit tricky. Any suggestions? My code in the controller looks something like this:
$scope.edit = function(id) {
myApp.edit($scope.svc, id)
.then(function(data) {
$scope.record = data;
}, function() {
console.log('error in removing the record : ' + id);
});
};
$scope.add = function() {
console.log($scope.record);
myApp.add($scope.svc, $scope.record)
.then(function(data) {
refresh();
}, function() {
console.log('error in adding the record : ');
});
};
$scope.update = function() {
console.log($scope.record);
myApp.update($scope.svc, $scope.record)
.then(function(data) {
refresh();
}, function() {
console.log('error in adding the record : ');
});
};
}
You didn't really highlight what error / issue you were having but I'll show you how I'd implement this:
Create one global record variable in your controller.
Each time a record is clicked, set the global record variable to be the clicked record. Then on your two buttons you simply invoke the edit / delete functions which work off of the global record variable.
On your table row repeater:
<tr ... ng-repeat="record of records" ng-click="setActiveRecord(record)">
In your controller:
$scope.activeRecord = {}
$scope.setActiveRecord = (record) => { $scope.activeRecord = record }
$scope.add = () => { ... }
$scope.edit = (record) => { /* your edit logic using $scope.activeRecord */ }
$scope.delete = (record) => { /* your delete logic using $scope.activeRecord */ }
As some basic UX you'd want to show which record is currently active, so perhaps by using ng-class:
<tr ... ng-repeat="record of records" ng-class="{ 'your-css-classname' : record.id === activeRecord.id }">

AngularJs/Nodejs updating view and animating it

I'm writing
angularjs/nodejs
I useed $http service to load my data from database and ngRepeat directive to display it into the view. What I can't do is when I add new item to database, update my view with just one item, and do it with animation.I know need to use ngAniamte and set class on ng enter but how do i push single item into data array without reloading the whole view?
Data Load and Insert
vm.loadData = function () {
$http.get('/data')
.success(function (data) {
vm.data = data;
})
.error(function (data) {
console.log('Error: ' + data);
});
}
http.post('/data', data).success(function (data) {
})
I assume vm.data is an array? You should not reassign the complete array but rather add new items to it, delete old items from it and/or update items in it. You can add new items with vm.data.push() and add/delete items with vm.data.splice(). To do this, you need to compare vm.data with data to determine which items need to be added/deleted/modified.

when i click on update button i got data to be updated but it gets cleared when i move to update page in angularjs

$scope.fetchDataForEditInvoice = function (row)
{
var index = $scope.gridOptions.data.indexOf(row.entity);
var InvoiceId = $scope.gridOptions.data[index].InvoiceId;
var status = angularService.FetchDataForEditInvoice(InvoiceId);
status.then(function (invoiceData) {
console.log(invoiceData);
window.location.href = "/Invoice/AddInvoice";
$scope.InvoiceDetails = invoiceData.data.InvoiceDetails;
},
function () {
alert('Error in fetching record.');
})
}
on click of update button i call following function and i got data but how i can assign it to controls on update page
save invoiceData.data.InvoiceDetails in a $rootScope variable. So it will available in all controllers.
$rootScope.InvoiceDetails=invoiceData.data.InvoiceDetails;
inject $rootScope to your controller before using it.
Use routers traversing next page.Refer Single Page Apps with AngularJS Routing]1

Programmatically Select AngularJS Typeahead Option

I have a AngularJS Typeahead that retrieves matches asynchronously. When a barcode is scanned into the field, it returns the matching result, but the user still has to select it. I would like to automatically select the result if it's an exact match. I see that the typeahead has a select(idx) function, but am not sure how to get a reference to it from my controller.
I was envisioning something like this:
$scope.SearchItems = function (term) {
return $http.get('api/Items/Search', {
params: {
term: term
}
}).then(function (response) {
if (response.data.length == 1 && response.data[0].Code == term) {
// Somehow inform typeahead control to select response.data[0]
}
return response.data;
});
};
I had a similar issue and never figured how to access the typeahead's select(idx), but I managed to get this functionality working. Here's my hacky workaround....
$promise.then(function(res) {
angular.forEach(res, function(item, key) {
// if we have an exact match
if (item.title === term) {
// update model
$scope.src = item;
// find item in dropdown
var elm = '[id*=option-' + key + ']';
var opt = angular.element(document.querySelectorAll(elm));
//call click handler outside of digest loop
$timeout(function() {
opt.triggerHandler('click');
}, 0);
}
});
// return async results
return res;
});
Basically we just update our model manually, locate the element in our dropdown and then fire off the 'click' handler. Make sure you wrap the triggerHandler call in a $timeout() set to zero, otherwise you will get a $rootScope:inprog error since digest is already in progress.

Can you bind data from one scope to update when another changes in angularJS

My web app depends on one specific variable changing throughout the user's visit. It controls what data the user will see at any given time, essentially akin to a TAG.
If the $scope.tagid = 1, is it possible to have another angular model to instantly update its own dataset when tagid is changed to $scop.tagid = 2?
<script >
function PageCtrl($scope) {
$scope.text = '<?=$tagid?>';
}
$scope.showThread = function(tagid) {
$http({method: 'GET', url: 'api/example/thread/id/' + tagid}).
success(function(data, status, headers, config) {
$scope.appDetail = data; //set view model
$scope.view = './Partials/detail.html'; //set to detail view
}).
error(function(data, status, headers, config) {
$scope.appDetail = data || "Request failed";
$scope.status = status;
$scope.view = './Partials/detail.html';
});
}
</script>
<div ng-controller="PageCtrl">
<input ng-model='text' />
<ul>
<li >
<span>{{text}}</span>
</li>
</ul>
</div>
Above is the skeleton of what i'm looking to do.
I realize that if I wanted to, I could call showThread() after each user action and update the data...however, because of the awy I'm looking to set up the site, It makes more sense to only change the tagid, then have everything else update immediately after, rather than picking and choosing each part of the site I want to update. i.e. there may, in addition to showThread(), be updateHeader(), changeSidebar() etc.
Thanks!
I have personally had success using a service; **Assuming that you are using 2 controllers on 1 page, I would create a service like this:
MyApp.app.service("tagDataSvc", function () {
var _tagId = {};
return {
getTagId: function () {
return _tagId;
},
setTagId: function (value) {
_tagId = value;
}
};
});
Next, inject this service into the controllers where this will be used.
In your main controller where you are controlling the TagId (PageCtrl), you would need to set the shared tagId value with a call to the service: tagDataSvc.setTagId($scope.text) You can do this explicitly, or add a $watch on $scope.text, or whatever you prefer.
Finally, in the second controller that you want to automagically update, add a $watch on this service's getTagId() function like so:
$scope.$watch(function () { return tagDataSvc.getTagId(); }, function (newValue, oldValue) {
if (newValue != null) {
$scope.tagId2 = newValue;
//reload whatever needs updating here
}
}, true);

Resources