ng-change directive doesn't work as expected - angularjs

In $scope.invoicename are stored data for invoices with id, name, and pdfmake for each invoice. When user select invoice name, it should display pdf document designed by selected pdfmake. This is my html for select
<select class="form-control" ng-change="zafakturu(dizajn.pdfmake)" ng-model="dizajn.pdfmake">
<option value={{dizajn.pdfmake}} ng-repeat="dizajn in invoicename" selected="selected">{{dizajn.name}}</option>
</select>
And here are function called on change and function makeInvoice which should display pdf document.
var makeInvoice = function(doc){
pdfMake.createPdf(doc).getDataUrl(function(dataURL) {
$scope.fajll= dataURL;
});
console.log(doc);
};
$scope.zafakturu = function (pdf){
$scope.docDefinition = eval("(" + pdf + ")");
makeInvoice($scope.docDefinition);
};
And here is html element which displays pdf.
<object ng-show="fajll" data="{{fajll}}" type="application/pdf" style="width: 100%; height: 400px;"></object>
The problem is, when I select one value, pdf with that value shows after second selection. For example, if I have options 1, 2, 3, and I select option 2, pdfmake for that option will display only after I select 1 or 3. If anyone could help?

Use $scope.$apply to make the AngularJS framework aware of changes to the scope variable.
pdfMake.createPdf(doc).getDataUrl(function(dataURL) {
$scope.fajll= dataURL;
$scope.$apply();
});
The function furnished as an argument to the .getDataURl method is being executed asynchronously outside of the AngularJS framework. The data attribute of the object element only gets updated after a digest cycle. $scope.$apply creates the necessary digest cycle.

Related

Angular ng-options ONLY works when ng-repeat operates on same model

I am working on an ASP.Net MVC page that uses a dropdown which currently uses the ng-repeat tag. I'm working to solve the problem where the dropdown does not correctly select the current model value when the page loads so I switched the dropdown to use ng-options.
My new dropdown looks like this:
<select id="one" ng-model="data.CommandProvider"
ng-options="item.ident as item.ProviderName for item in providers">
</select>
When the page loads my new select displays as a large empty rectangle. It's approximately the width and height to match the three items it should contain but it's not a dropdown. No options and no dropdown button.
However, when I follow the new dropdown with the old dropdown like so:
<select id="one" ng-model="data.CommandProvider"
ng-options="item.ident as item.ProviderName for item in providers">
</select>
<select id="two" ng-model="data.CommandProvider">
<option ng-repeat="opt in providers track by opt.ident"
value="{{opt.ident}}">
{{opt.ProviderName}}
</option>
</select>
BOTH dropdowns load their options correctly but NEITHER dropdown correctly displays the current value of the model.
If the page only contains the old dropdown based on ng-repeat that dropdown displays correctly.
I don't understand what could cause such behavior in ng-options and what would cause the dropdowns to never correctly represent the model on page load?
ADDED: So the previous author had mismatched HTML tags and that was causing the error with the new dropdown - why it didn't break the original I don't know. That being said the new dropdown STILL does not display the value of the model when the page is loaded.
So after working this problem for too long this is the solution that worked for me:
There are three http requests in play: one for each select input and one for the model data and whenever the model data returned before the select data one or both of the select would be out of sync with the model. My solution was to synchronize the data requests.
The select inputs:
<select ng-model="data.Connection">
<option ng-repeat="opt in connections track by opt.ident" value="{{opt.ident}}">{{opt.ConnectionName}}</option>
</select>
<select id="two" ng-model="data.CommandProvider">
<option ng-repeat="opt in providers track by opt.ident" value="{{opt.ident}}">{{opt.ProviderName}}</option>
</select>
The javascript:
// connection and provider data variables
$scope.providers;
$scope.connections;
// function to retrieve connection dropdown data
$scope.getConnections = function () {
$scope.getApiData('GetConnections',
{}, function (data) {
$scope.connections = data;
});
}
// function to retrieve the provider dropdown data
$scope.getProviders = function () {
$scope.getApiData('GetProviders',
{}, function (data) {
$scope.providers = data;
});
}
// retrieve the primary page data
$scope.getCommandData = function () {
$scope.getApiCommandDataV1('GetCommandById',
{Id: #ViewBag.ID},
function (data) {
$scope.data = data;
});
}
// retrieves data from the core api
$scope.getApiData = function (alias, params, successFn, errorFn = null) {
var qdata = { SqlAlias: alias, SqlParameters: params };
if (errorFn == null) {
$http.post('/api/request', qdata).success(successFn);
} else {
$http.post('/api/request', qdata).success(successFn).error(errorFn);
}
}
// function to request the data for the page
$scope.init = function () {
$scope.getConnections();
}
// set a watch on the connections variable to fire when the data
// returns from the server - this requests the Providers information.
$scope.$watch('connections', function (newValue, oldValue, scope) {
if (newValue == undefined || newValue == null)
return;
$scope.getProviders();
}, true);
// set a watch function on the providers variable to fire when the data
// returns from the server - this requests the primary data for the Command.
$scope.$watch('providers', function (newValue, oldValue, scope) {
if (newValue == undefined || newValue == null)
return;
$scope.getCommandData();
}, true);
// initialize the page logic and data
$scope.init();
As you can see my use of $scope.$watch forces the data requests to be synchronous rather than asynchronous and using this method insures the two select inputs are correct every time the web page loads.
Feel free to comment on my coding here as there may be better ways to address this problem - just keep in mind that I have only been working with JavaScript and Angular for about a month.

angularjs 2 select box loaded data but select box is not visible on browser

I have a select box which is populating from database. In the browser, I can see the select box template with all data from DB but not able to see the select box in the UI in a table.
Controller.js:
$scope.GetCvSRCDetails = function() {
$scope.loader.loading = true;
crudFactory.getDataList("getcvsrcadetailalerts", "null")
.success(function (rcdata) {
$scope.cvsRCDetails = rcdata;
});
};
$scope.GetCvSRCDetails();
crudfactory.js
getDataList: function (ctrName, objId) {
url = serviceBase + "api/" + ctrName + "/" + objId;
return $http.get(url);//, authService.setHeader($http));
},
HTML
<td>
<select data-ng-options="rc.RCL1 for rc in cvsRCDetails"
data-ng-model="col">
</select>
</td>
On the basis of this, I need to populate another select box, but first I am not able to see the first Select box.
Thanks.
I resolved this issue with using below code.
<select ng-model="col" material-select>
<option ng-repeat="rc in cvsRCDetails">{{rc.RCL1}}</option>
</select>
I just added material-select in select tag.
Thanks,
Bharat

Kendo DropDownList not displaying selected item

I am trying to use a pair of Kendo dropdown lists to filter a dataset in AngularJS. One uses a static ObservableArray datasource to filter the dataset by status; the other datasource is a set of distinct values from the "regionID" column of the dataset, also stored as an ObservableArray. When the status dropdown changes, the region dropdown is supposed to reload the list of regions from the newly-filtered data. This works, but the selected value ends up blanked out, even though the model that's supposed to represent the selected value still has the correct value, and the data is still correctly filtered by that same value. Opening the dropdown and then clicking off of it causes it to then display that value as it should.
Here is what the HTML looks like:
<select name="filterByRegion" style="width: 180px;" class="form-control" ng-model="selectedRegion" ng-change="onRegionFilterChange(selectedRegion)" kendo-drop-down-list k-options="regionFilterOptions"></select>
<select name="accountStatus" style="width: 180px;" class="form-control" ng-model="status" ng-change="onAccountStatusChange(status)" kendo-drop-down-list k-options="accountStatusOptions"></select>
Here are the two "onChange" methods from the controller:
$scope.onAccountStatusChange = function(status) {
$scope.status = status;
updateRegionFilterList();
};
$scope.onRegionFilterChange = function(selectedRegion) {
$scope.selectedRegion = selectedRegion;
};
And lastly, here is the updateRegionFilterList method:
var updateRegionFilterList = function () {
$scope.regions.empty();
angular.forEach($scope.accounts, function(account) {
if (account.reviewStatus === $scope.status) {
if ($scope.regions.indexOf(account.regionID) <= -1) {
$scope.regions.push(account.regionID);
}
}
});
$scope.regions.sort();
$scope.regions.unshift("Filter By Region:");
if ($scope.regions.indexOf(tempRegion) <= -1) {
$scope.selectedRegion = "Filter By Region";
}
};
I have tried many ways of working around this, including trying to preserve and reload the selectedRegion value, splicing out unneeded regions instead of emptying the ObservableArray, etc., and I have checked everything in the debugger and all of the values are correct (no obvious race conditions either).
Any ideas?
I figured it out. I had mixed kendo and angular configurations with the dropdowns and was relying on an angular process to update the data, which wasn't updating the Kendo MVVM stuff properly. Switching it to pure Kendo did the trick.

auto refresh of page in angularjs

I am trying to refresh the page based on value selected. Initially i had set the meta tag to refresh the page for 10 secs. Later when a particular value is selected from combo, the page should get refreshed based on the value selected.
There is a buildchart function which gets executed when i load the page or when refreshed. This function gets a json file from a location. The json file gets updated every few minutes. So after few intervals i will be getting the updated json file in a configured location . So i am configuring a combo box with values so that when the user selects the value, after that much secs the json is fetched and the report displayed.
HTML
<meta id="refresh" http-equiv="refresh" content="10;URL=/index.html#/Refresh">
Later in the code:
<select style="text-align: right;" name="refreshrate"
ng-model="model.refreshrate"
ng-options= "item.value as item.label for item in refreshValues "
ng-change = "TimedRefresh(model.refreshrate)">
</select>
My angular code
$scope.refreshValues =
[
{label:"1 Min", value:"1"},
{label:"3 Min", value:"3"},
{label:"5 Min", value:"5"},
{label:"Never", value:"0"}
];
$scope.TimedRefresh = function(t) {
console.log(t);
setTimeout("location.reload(true);", t*60);
}
However, the page refreshes with the already configured value of 10 in the meta tag's content. what am i missing to update this?
UPDATE
I tried changing the meta tag during runtime when the value is selected, now the page refresh happens but only once at the specified selected interval and not repeatedly after that.
$scope.TimedRefresh = function(t) {
console.log(t);
var s = document.getElementById('refresh');
s.setAttribute("content", t*10 +";URL=index.html#/Refresh");
console.log(s);
}
I removed the content attribute from the meta tag and assigned it at runtime. However i am trying to refresh the page not once but every configured interval times.
Try
$route.reload(); or $window.location.reload();
The meta-tag will refresh the page no matter what. You should call TimedRefresh(10) in the controller, so when it loads, the function get called.
app.controller('myCtrl', function() {
$scope.refreshValues = [
{label:"1 Min", value:"1"},
{label:"3 Min", value:"3"},
{label:"5 Min", value:"5"},
{label:"Never", value:"0"}
];
$scope.TimedRefresh = function(t) {
console.log(t);
setTimeout("location.reload(true);", t*60);
}
$scope.TimedRefresh(10); // Will trigger TimedRefresh(10) once when the controller loads
// ...
});
I'm curious on what you are trying to do though. Can you elaborate?

How to update model on select inside of ng-repeat?

The widget inside the Child scope, with the ng-repeated div and select dropdown:
<div ng-repeat="term in ticker.terms">
<select ng-model="term.chosenTag" ng-change="ticker.changeTag(term)">
<option>...</option>
<option>...</option>
<option>...</option>
I'm trying to change ^ term.chosenTag from the parent scope, term is the repeated data object (term in terms)
Full code Gists:
Main Parent HTML: https://gist.github.com/leongaban/e0154005bed6b6892df7
Ticker Child HTML
https://gist.github.com/leongaban/9a5fd86643051fd9e1af
TickerController (Child)
https://gist.github.com/leongaban/2d58174cfe6e5c9c0465
MainController (Parent)
https://gist.github.com/leongaban/1563b09b906337a3e6ad
TagFactory
https://gist.github.com/leongaban/8db5027e1cb86f614fa5
Now the select in the parent scope that needs to also control the model in the child select:
<select ng-model="main.selected_tag"
ng-change="main.changeTag(main.the_tag)">
That main.changeTag function calls this:
vm.changeTag = function(term) {
// Update tag in model:
TagFactory.updateTag(term);
};
TagFactory then updates the term on the database as well as my model:
// Update tag:
tags.updateTag = function(data) {
var tag = data;
// Filter and find tag by id:
var tagObj = {};
tagObj = $filter('filter')(tags, { term_id: tag.term_id })[0];
// Update tag in model:
tagObj.tag = tag.chosenTag;
/**
* PUT : update tag on DB
*/
ApiFactory.updateTag(
tag.term_id,
tag.chosenTag,
tag.ticker).then(function(data) {
console.log('PUT:');
console.log(data);
});
return tag;
};
Since you fire your updateTag call onchange, as opposed to onclick, I am going to assume that constantly updating the service's data is OK. The other method where this wouldn't be advisable is if you only want to push data to the service at certain times, to avoid all your templates from seeing the changes to the factory data immediately if you still need to execute AJAX.
In the appropriate controller, with TagFactory injected, create a reference to the factory's data:
$scope.tags = TagFactory.tags;
Then your HTML can directly modify the TagFactory itself:
<div ng-repeat="tag in /*expression that determines ticker.terms with respect to $scope.tags*/">
<select ng-model="tag.chosenTag">
The expression can be as simple as "tags", but it will probably need to involve a filter that only returns tags that are ticker.terms.

Resources