Computed values in angular-schema-form - angularjs

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>

Related

AngularJs ng-repeat does not order time list after scope change

I try to reorder ng-repeat list after $scope change
<div ng-repeat="item in model.itemList | orderBy:order">
<input ng-blur="setOrder('start')"
ng-change="timeSpanChange(item.start,start.newTime);"
ng-model="start.newTime" ng-value="item.start|showTimeSpan"
type="time" />
</div>
And I have angular code:
app.controller('ctl', function ($scope, $http, $timeout) {
$scope.order = 'start';
$scope.model = {
"itemList": [
{ "start":new Date(2000,01,01,10,00,00) },
{ "start":new Date(2000,01,01,11,00,00) },
{ "start":new Date(2000,01,01,12,00,00) }
]
}
$scope.setOrder = function (order) {
$scope.order = order;
};
$scope.timeSpanChange = function (item, time) {
item.Hours = time.getHours();
item.Minutes = time.getMinutes();
};
}).filter('showTimeSpan', function () {
return function (time) {
return String(time.Hours).padStart(2, '0') + ":" + String(time.Minutes).padStart(2, '0');
};
});
I see that model has change after ng-blur, but ng-repeat is still ordered as on first load
What i'm doing wrong, should I refresh scope before reorder?
order should be a property in the itemList. I'm assuming you are not changing the sort order.
<div ng-repeat="item in model.itemList | orderBy:'start'">
The orderBy filter sorts JavaScript Date objects by date and time. Use a custom predicate function to sort by time only:
$scope.timeOnlyFn = function(item) {
var timeOnly = item.datetime.valueOf() % (24*60*60*1000);
return timeOnly;
}
The DEMO
angular.module("app",[])
.controller('ctrl', function ($scope, $http, $timeout) {
$scope.order = 'datetime';
$scope.model = {
"itemList": [
{ "datetime": new Date("2019-02-07T09:00"), name: "Baker" },
{ "datetime": new Date("2019-07-07T08:00"), name: "Charlie" },
{ "datetime": new Date("2019-02-07T10:00"), name: "Adam" }
]
}
$scope.timeOnlyFn = function(item) {
var timeOnly = item.datetime.valueOf() % (24*60*60*1000);
return timeOnly;
}
$scope.setOrder = function (order) {
$scope.order = order;
};
});
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="app" ng-controller="ctrl">
<div ng-repeat="item in model.itemList | orderBy:order">
<input ng-model="item.datetime" type="date" />
<input ng-model="item.datetime" type="time" />
{{item.name}}
</div>
<br>
<button ng-click="order='name'">Order by Name</button>
<button ng-click="order='datetime'">Order by DateTime</button>
<button ng-click="order=timeOnlyFn">Order by TimeOnly</button>
</body>
Thanks a lot georgeawg, that's exactly what I need, but I suppose my problem starts in the model.
In fact I'm getting json from controller and it isn't UTC but C# TimeSpan object {"Hours":16,"Minutes":8,"Seconds":45,"Milliseconds":....., that's why i used ng filter to map it with <input type='time'>
Is the properly way to make two-way binding model property with C# time span; or
should I convert it in controller?

AngularJS - Watch filtered list for changes

Within angular I have a filtered list of people that takes the filter criteria from a predicate function. I want to watch a variable of the filtered list (called filteredPeople) every time the filtered list changes. But I am unable to see when that variable changes.
My code is below:
HTML:
<ul>
<li ng-repeat="person in ($ctrl.filteredPeople = ($ctrl.people | filter: $ctrl.filter))">
...
</li>
</ul>
JS:
controller: ['$scope',
function ($scope) {
var $ctrl = this;
$ctrl.people = {...}
$ctrl.filteredPeople = [];
$scope.$watch($ctrl.filteredPeople, function () {
console.log("called"); //not being called
});
$ctrl.filter = function (p) {
//custom filter function for each item in the array of people
}
}]
I can answer any questions of provide more code if needed
angular.module('app', []).controller('ctrl', function($scope) {
var vm = this;
vm.items = [
{ name: 'Sam' },
{ name: 'Max' },
{ name: 'Tom' },
{ name: 'Henry' },
{ name: 'Jack' },
{ name: 'Kate' }
]
var counter = 1;
$scope.$watchCollection('vm.filtered', function(){
console.log('Changed' + counter++);
})
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js">
</script>
<div ng-app='app' ng-controller='ctrl as vm'>
<input type='text' ng-model='vm.filter' />
<ul>
<li ng-repeat='item in vm.filtered = (vm.items | filter : vm.filter)'>{{item}}</li>
</ul>
</div>

AngularJS $http.get function not executed second time

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.

Factory value not updated in model ...what I am doing wrong?

I am new to angular-js. I have two controllers (welcomeContoller,productController) and both handling the same model within the factory.
When the model getting updating by one controller(productController) it should reflect the update in another controller. (welcomeContoller)
But its not happening now.
HTML code :
<body ng-app="myApp">
<div ng-controller="welcomeContoller">
{{totalProductCnt}}
</div>
<div ng-controller="productController">
<div class="addRemoveCart">
<span class="pull-left glyphicon glyphicon-minus" ng-click="removeProduct()"></span>
<span class="pull-right glyphicon glyphicon-plus" ng-click="addProduct(1)"></span>
</div>
</div>
JS code
var myApp = angular.module("myApp", ['ui.bootstrap']);
myApp.factory("productCountFactory", function() {
return {
totalProducts:0
};
});
myApp.controller("welcomeContoller", function($scope, productCountFactory)
{
$scope.totalProductCnt = productCountFactory.totalProducts;
});
myApp.controller("productController", function($scope, productCountFactory) {
$scope.addProduct = function() {
productCountFactory.totalProducts++;
alert(productCountFactory.totalProducts);
};
$scope.removeProduct = function() {
if(productCountFactory.totalProducts >=1)
productCountFactory.totalProducts--;
alert(productCountFactory.totalProducts);
};
});
Even after the addProduct is called the totalProductCnt is displaying as zero. I want to display the value for each increment.
Plunkr Link
Put the factory object reference on scope:
myApp.controller("welcomeContoller", function($scope, productCountFactory) {
$scope.productCountFactory = productCountFactory;
});
Watch the property of the object.
{{productCountFactory.totalProducts}}
The DEMO on PLNKR.
By putting a reference on scope, on every digest cycle the watcher looks up the value of the property and updates the DOM if there is a change.
The totalProductCnt from your welcomeController isn't updated because it is assigned only once when the controller is created.
You can use several solutions to refresh the displayed value. Use a getter for your totalProducts in the factory :
myApp.factory("productCountFactory", function() {
var totalProducts = 0;
return {
getTotalProducts: function() {
return totalProducts;
},
addProduct: function() {
totalProducts++;
},
removeProduct: function() {
totalProducts--;
}
};
});
myApp.controller("welcomeContoller", function($scope, productCountFactory) {
$scope.getTotalProducts = productCountFactory.getTotalProducts;
});
myApp.controller("productController", function($scope, productCountFactory) {
$scope.addProduct = function() {
productCountFactory.addProduct();
};
$scope.removeProduct = function() {
if (productCountFactory.getTotalProducts() >= 1)
productCountFactory.removeProduct();
};
});
And update the view accordingly:
<div ng-controller="welcomeContoller">
{{getTotalProducts()}}
</div>
Plunkr Link

I'm looking for a way to take the hard coded "Character" data in my Angular app and load it from a separate json file

I'm looking for a way to take the hard coded "Character" data in my Angular app and load it from a separate json file.
I have a controller for the ($http) thats worked in other apps, I'm just not sure how to strip, pull and access these character names and properties from a JSON file. Any help would be appreciated.
<body>
<div class="container">
<div ng-app="polarisApp">
<h1>The Other Guys</h1>
<h3>Custom Events in Nested Controllers</h3>
<div ng-controller="Characters">
<div class="lList"> <span ng-repeat="name in names" ng-click="changeName()">{{name}}</span>
</div>
<div class="cInfo">
<div ng-controller="Character">
<label>Name:</label>{{currentName}}
<br>
<label>Job:</label>{{currentInfo.job}}
<br>
<label>Weapon:</label>{{currentInfo.weapon}}
<br> <span ng-click="deleteChar()">Delete</span>
</div>
</div>
</div>
</div>
<script src="http://code.angularjs.org/1.3.0/angular.min.js"></script>
<script src="angular.js"></script>
<script>
angular.module('polarisApp', [])
.controller('Characters', function ($scope) {
$scope.names = ['Alan', 'Terry', 'Gene', 'Sheila', 'Danson', 'Highsmith', 'Bob'];
$scope.currentName = $scope.names[0];
$scope.changeName = function () {
$scope.currentName = this.name;
$scope.$broadcast('CharacterChanged', this.name);
};
$scope.$on('CharacterDeleted', function (event, removeName) {
var i = $scope.names.indexOf(removeName);
$scope.names.splice(i, 1);
$scope.currentName = $scope.names[0];
$scope.$broadcast('CharacterChanged', $scope.currentName);
});
})
.controller('Character', function ($scope) {
$scope.info = {
'Alan': {
weapon: 'Calculator',
job: 'Police Officer'
},
'Terry': {
weapon: 'Gun',
job: 'Police Officer'
},
'Gene': {
weapon: 'None',
job: 'Police Captain'
},
'Sheila': {
weapon: 'None',
job: 'M D'
},
'Danson': {
weapon: 'Gun',
job: 'Police Detective'
},
'Highsmith': {
weapon: 'Gun',
job: 'Police Detective'
},
'Bob': {
weapon: 'None',
job: 'Police Accountant'
}
};
$scope.currentInfo = $scope.info['Alan'];
$scope.$on('CharacterChanged', function (event, newCharacter) {
$scope.currentInfo = $scope.info[newCharacter];
});
$scope.deleteChar = function () {
delete $scope.info[$scope.currentName];
$scope.$emit('CharacterDeleted', $scope.currentName);
};
});
</script>
</body>
This is the ($http) controller I wrote.
angular.module('polarisApp')
.controller('MainCtrl', function ($scope, $http) {
$http.get('character.json')
.success(function(data) {
$scope.characterStatus = data.caracterStatus;
});
You can try this
var info = null;
$http.get('character.json').success(function(data) {
info = data;
});
The response from the $http.get request will be the object contained in content.json file. If you need to access Alan's job, you can use info.Alan.job and so on.
I got it working with this controller:
App.controller('CharacterCtrl', function($scope, $http) {
$http.get('characters.json')
.then(function(res){
$scope.characters = res.data;
}); });
Thank you very much for your feedback. I haven't seen that variable you used in any similar controllers. I think I should look into it--Might be missing out on a better way to $http. Thanks.

Resources