AngularJS $http.get function not executed second time - angularjs

I have a requirement to create a multiselect dropdown using angularjs with values coming from database based on different parameters.I have implemented following code. It is working fine when the page loads at first time. If come to this page second time, the $http.get function is not executing and still showing the same data as in the first page load.
This is my .js file:
var app = angular.module("myModule", ["angularjs-dropdown-multiselect"]);
app.controller("myController", ['$scope','$http', function ($scope,$http) {
$scope.AllDescriptions = [];
$scope.DescriptionsSelected = [];
$scope.dropdownSetting = {
scrollable: true,
scrollableHeight: '200px'
};
$http.get('/Areaname/ControllerName/MethodName').then(function (data) {
angular.forEach(data.data, function (value, index) {
$scope.AllDescriptions.push({ id: value, label: value });
});
});
}])
This is my html file :
<div ng-app="myModule" ng-controller="myController" >
<div class="container">
<div id="divRight" style="min-height:5px;display: inline-block; width: 40%; vertical-align: top;">
<label style="float:left;">Error Description : </label>
<div style="float:left;width:200px;margin-left:10px" ng-dropdown-multiselect="" extra-settings="dropdownSetting" options="AllDescriptions" selected-model="DescriptionsSelected" checkboxes="true"></div>
</div>
</div>
</div>
This is my .cs file :
public JsonResult MethodName()
{
List<string> errorDescriptions = //Get from server
return new JsonResult() { Data=errorDescriptions,JsonRequestBehavior=JsonRequestBehavior.AllowGet};
}
Kindly help me to execute this JSON method for every page request instead of only in the first page request. Thank you.

I think the problem is with cache. Try to put your get method in variable ($scope.GetDescriptions = function () { $http.get... }) and use ng-init directive
(<div class="container" ng-init="GetDescriptions()">). Also try to empty array before push elements in it ($scope.AllDescriptions = [], $scope.AllDescriptions.push(...)

Try adding $route.reload(), this reinitialise the controllers but not the services:
app.controller("myController", ['$scope','$http','$route' function ($scope,$http,$route) {
$route.reload(); // try pass parameter true to force
$scope.AllDescriptions = [];
$scope.DescriptionsSelected = [];
$scope.dropdownSetting = {
scrollable: true,
scrollableHeight: '200px'
};
$http.get('/Areaname/ControllerName/MethodName').then(function (data) {
angular.forEach(data.data, function (value, index) {
$scope.AllDescriptions.push({ id: value, label: value });
});
});
}])
If you want to reset the whole state of your application you can use $window.location.reload(); instead route like:
app.controller("myController", ['$scope','$http','$route' function ($scope,$http,$route) {
$window.location.reload(); // try pass parameter true to force
$scope.AllDescriptions = [];
$scope.DescriptionsSelected = [];
$scope.dropdownSetting = {
scrollable: true,
scrollableHeight: '200px'
};
$http.get('/Areaname/ControllerName/MethodName').then(function (data) {
angular.forEach(data.data, function (value, index) {
$scope.AllDescriptions.push({ id: value, label: value });
});
});
}])
Hope this works.

Related

Initialise AngularJS service - factory on the document load

Sorry for a very stupid question but I just started working with AngularJS and OnsenUI.
I have got a service to get a data from SQLite:
module.factory('$update', function () {
var update = {};
db.transaction(function (tx) {
tx.executeSql('SELECT * FROM event_updates', [], function (tx, results) {
var rows = results.rows;
update.items = [];
if (!rows.length) {} else {
for (var index = 0; index < rows.length; index++) {
update.items.push({
"title": rows.item(index).title,
"date": rows.item(index).date,
"desc": rows.item(index).desc
});
}
}
}, function (error) {
console.log(error);
});
});
return update;
});
And a controller which is using the data:
module.controller('UpdatesController', function ($scope, $update) {
$scope.items = $update.items;
});
As soon as my page is loaded the content is not displayed and I need to click twice to call a page with the code below to see the content:
<ons-list ng-controller="UpdatesController">
<ons-list-item modifier="chevron" class="list-item-container" ng-repeat="item in items" ng-click="showUpdate($index)">
<div class="list-item-left">
</div>
<div class="list-item-right">
<div class="list-item-content">
<div class="name">{{item.title}}</div> <span class="desc">{{item.desc}}</span>
</div>
</div>
</ons-list-item>
</ons-list>
Can anybody help how can I initialise the controller as soon as page is loaded with all content. Sorry if it is a stupid question but I am really struggling. Appreciate your help a lot.
You could store the result of the request in the factory and retrieve those instead.
module.factory('$update', function () {
var update = {};
var requestValues = function(){ // store the results of the request in 'update'
// Your db.transaction function here
}
var getUpdates = function(){ // retrieve the values from 'update'
return update;
}
return{
requestValues : requestValues,
getUpdates : getUpdates
}
});
And then in you controller:
module.controller('UpdatesController', function ($scope, $update) {
$update.requestValues();
$scope.items = $update.getUpdates();
});
You could then get the values from anywhere in you solution (by using $update.getUpdates) without having to make an extra http request.

Angular Factory data isn't shared correctly

I'm trying to share some data from the controller in the current view to my navigation bar. but the data is shared wrong, or not synced correctly.
this is my factory:
myApp.factory('HeaderData', function () {
var data = {
Visible: true,
PageTitle: ''
};
return {
getVisible: function () {
return data.Visible;
},
setVisible: function (visible) {
data.Visible = visible;
console.log("HeaderData: " +visible);
},
getPageTitle: function () {
return data.PageTitle;
},
setPageTitle: function (title) {
data.PageTitle = title;
}
};
});
then in my controllers I'm doing the following:
myApp.controller('homeCtrl',function ($scope, HeaderData) {
HeaderData.setVisible(false);
console.log("HomeCtrl: " + HeaderData.getVisible());
});
in the Nav controller I read the data in like following:
myApp.controller('navCtrl', function ($scope, HeaderData) {
console.log("NavCtrl: " +HeaderData.getVisible());
$scope.showHeader = HeaderData.getVisible();
$scope.pageTitle = HeaderData.getPageTitle();
});
the following output is logged:
NavCtrl: true
HeaderData: false
HomeCtrl: false
So my NavContrl is loaded before my Data is set, and this is logical because it's like this in the HTML:
<div ng-controller="navCtrl">
<ng-include ng-show="showHeader" src="'../partials/common/header.html'"></ng-include>
</div>
<div ng-view></div>
So how can I make it work that my navCtrl updates the data correctly, and in this example hide the header when the $scope.showHeader is set to false?
Instead of assigning a primitive to $scope, assign an object to scope so that you can bind by reference. By binding by reference, you ensure that scope properties resolve to the same reference.
When you bind to a primitive (string, int, etc), it creates a copy of the original value on scope as soon as it is assigned. Now you have multiple copies of the variable on different scopes, and they all behave independently of each other.
myApp.factory('HeaderData', function() {
var data = {
Visible: true,
PageTitle: ''
};
return {
...
getData = function() {
return data;
}
};
});
And assign the model to scope:
myApp.controller('navCtrl', function($scope, HeaderData) {
$scope.data = HeaderData.getData();
});
And in your HTML:
<div ng-controller="navCtrl">
<div ng-show="data.Visible">HEADER</div>
</div>

Computed values in angular-schema-form

I have a form which is used to enter a bunch of values. I want to show various calculation on the values, but dynamically, so that when a number is changed the results immediately update. I thought that this should work, but it doesn't - i.e. the calculation is never run:
angular.module('calcs', ['schemaForm'])
.controller('CalcCtrl', function ($scope) {
$scope.schema = {
type: 'object',
properties: {
width: {
type: 'number',
title: 'Width'
},
depth: {
type: 'number',
title: 'Depth'
}
}
};
$scope.form = ['*'];
$scope.model = {};
$scope.$watch('[model.width, model.depth]', function() {
// This function is never called
$scope.area = $scope.model.width * $scope.model.depth;
});
});
I have seen this question, but I am doing quite a number of calculations and I really don't want to have to create a directive for each, so I am hoping there is another way. For reference, here is my template:
<div ng-controller="CalcCtrl">
<form sf-schema="schema" sf-form="form" sf-model="model"></form>
<p>Area: {{area}}</p>
</div>
I believe what you want is $watchCollection:
$scope.$watchCollection('[model.width, model.depth]', function() {
// This function is never called
$scope.area = $scope.model.width * $scope.model.depth;
});
example:
var app = angular.module('app', []);
app.controller('myController', function($scope) {
$scope.model = {}
$scope.$watchCollection('[model.width,model.height]', function() {
$scope.area = $scope.model.width * $scope.model.height;
});
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="myController">
<input ng-model="model.width">
<input ng-model="model.height">
{{area || ''}}
</div>
<div>

Single Controller for multiple html section and data from ajax request angularjs

I'm trying to show two section of my html page with same json data, i don't want to wrap both in same controller as it is positioned in different areas. I have implemented that concept successfully by using local json data in "angular service" see the demo
<div ng-app="testApp">
<div ng-controller="nameCtrl">
Add New
Remove First
<ul id="first" class="navigation">
<li ng-repeat="myname in mynames">{{myname.name}}</li>
</ul>
</div>
<div>
Lot of things in between
</div>
<ul id="second" class="popup" ng-controller="nameCtrl">
<li ng-repeat="myname in mynames">{{myname.name}}</li>
</ul>
JS
var testApp = angular.module('testApp', []);
testApp.service('nameService', function($http) {
var me = this;
me.mynames = [
{
"name": "Funny1"
},
{
"name": "Funny2"
},
{
"name": "Funny3"
},
{
"name": "Funny4"
}
];
//How to do
/*this.getNavTools = function(){
return $http.get('http://localhost/data/name.json').then(function(result) {
me.mynames = result.mynames;
return result.data;
});
};*/
this.addName = function() {
me.mynames.push({
"name": "New Name"
});
};
this.removeName = function() {
me.mynames.pop();
};
});
testApp.controller('nameCtrl', function ($scope, nameService) {
$scope.mynames = nameService.mynames;
$scope.$watch(
function(){ return nameService },
function(newVal) {
$scope.mynames = newVal.mynames;
}
)
$scope.addName = function() {
nameService.addName();
}
$scope.removeName = function() {
nameService.removeName();
}
});
jsfiddle
Next thing i want to do is to make a http request to json file and load my two section with data, and if i add or remove it should reflect in both areas.
Any pointers or exisisitng demo will be much helpful.
Thanks
The reason why only one ngRepeat is updating is because they are bound to two different arrays.
How could it happen? It's because that you have called getNavTools() twice, and in each call, you have replaced mynames with a new array! Eventually, the addName() and removeName() are working on the last assigned array of mynames, so you're seeing the problem.
I have the fix for you:
testApp.service('nameService', function($http) {
var me = this;
me.mynames = []; // me.mynames should not be replaced by new result
this.getNavTools = function(){
return $http.post('/echo/json/', { data: data }).then(function(result) {
var myname_json = JSON.parse(result.config.data.data.json);
angular.copy(myname_json, me.mynames); // update mynames, not replace it
return me.mynames;
});
};
this.addName = function() {
me.mynames.push({
"name": "New Name"
});
};
this.removeName = function() {
me.mynames.pop();
};
});
testApp.controller('nameCtrl', function ($scope, nameService) {
// $scope.mynames = nameService.mynames; // remove, not needed
nameService.getNavTools().then(function() {
$scope.mynames = nameService.mynames;
});
/* Remove, not needed
$scope.$watch(
function(){ return nameService },
function(newVal) {
$scope.mynames = newVal.mynames;
}
);
*/
$scope.addName = function() {
nameService.addName();
};
$scope.removeName = function() {
nameService.removeName();
};
});
http://jsfiddle.net/z6fEf/9/
What you can do is to put the data in a parent scope (maybe in $rootScope) it will trigger the both views ,And you don't need to $watch here..
$rootScope.mynames = nameService.mynames;
See the jsFiddle

Re-binding a tree (Wijmo tree) with AngularJS

I am fairly new to AngularJS, and really struggling to re-bind a Wijmo tree (or even a tree implemented using UL and LI elements wth ng-repeat) with new data on changing of value of a Wijmo combobox (or, even a regular dropdown of HTML select elem).
Below is the code I have written, which is working fine in initial page load. But on changing the dropwdown, the tree is not being reloaded with new data fetched by loadDomainTree method; it is still showing old data. Can somebody help me figure out what's wrong with this code?
HTML:
<div ng-controller="DomainCtrl">
<select id="domain" ng-model="currentDomain" ng-options="item.Name for item in domainList"></select>
<div>
<ul id="wijtree">
<li ng-repeat="item in domainEntityList" id={{item.Id}}>
<a>{{item.Name}}</a>
</li>
</ul>
</div>
</div>
JS:
$(document).ready(function ()
{
$("#domain").wijcombobox({
isEditable: false
});
$("#wijtree").wijtree();
});
function DomainDropdownModel(data) {
this.Id = data.Id.toString();
this.Name = data.Name;
};
function DomainTreeModel(data) {
this.Id = data.Id;
this.Name = data.Name;
};
function DomainCtrl($scope, $locale) {
$scope.domainList = [];
$.ajax({
url: dropDownUrl,
async: false,
success: function (data) {
$(data).each(function (i, val) {
var domain = data[i];
var domainId = domain.Id.toString();
var domainName = domain.Name;
$scope.domainList.push(new DomainDropdownModel({ Id: domainId, Name: domainName }));
});
}
});
$scope.currentDomain = $scope.domainList[0];
$scope.loadDomainTree = function (domainId) {
domainEntitiesUrl = DOMAIN_API_URL + DOMAIN_ID_PARAM + domainId;
//alert(domainEntitiesUrl);
$scope.domainEntityList = [];
$.ajax({
url: domainEntitiesUrl,
async: false,
success: function (data) {
$(data).each(function (i, entity) {
var domainEntity = data[i];
var domainEntityId = domainEntity.Id.toString();
var domainEntityName = domainEntity.Name;
$scope.domainEntityList.push(new DomainTreeModel({ Id: domainEntityId, Name: domainEntityName }));
});
}
});
};
//Will be called on setting combobox dfault selection and on changing the combobox
$scope.$watch('currentDomain', function () {
$scope.loadDomainTree($scope.currentDomain.Id);
});
}
You may $watch for the selectedItem of WijCombobox and then, re-load the wijtree accordingly. Here is the code:
$scope.$watch('selectedItem', function (args) {
if (args === 'Tree 1') {
$("#wijtree").wijtree("option", "nodes", $scope.nodes1);
}
else {
$("#wijtree").wijtree("option", "nodes", $scope.nodes2);
}
});
HTML Code
<wij-combobox data-source="treeList" selected-value="selectedItem">
<data>
<label bind="name"></label>
<value bind="code"></value>
</data>
</wij-combobox>

Resources