Angular Watch Triggered if newValue changes - angularjs

I want to change value's based on other values in a repeat. I made a watch but the thing is that if i alter the newValue inside the watch the watch is triggered again.
Is there a way to solve this problem
my watch:
$scope.$watch('objlist', function(newValue, oldValue) {
$scope.counter += 1;
for (var count = 0; count < newValue.length; ++count) {
if (typeof newValue[count] != "undefined" && (typeof oldValue == "undefined" || newValue[count].value1 != oldValue[count].value1)) {
newValue[count].value3 = newValue[count].value1 * newValue[count].value2;
newValue[count].value3 = Number(newValue[count].value3).toFixed(2);
}
if (typeof newValue[count] != "undefined" && (typeof oldValue == "undefined" || newValue[count].value3 != oldValue[count].value3)) {
newValue[count].value1 = newValue[count].value3 / newValue[count].value2;
newValue[count].value1 = Number(newValue[count].value1).toFixed(2);
}
}
}, true);
i have included a plunker to show you what i mean.
plunker
as you can see if you change the value of field 1 or 3 it automaticly adds 2 to the counter and sets both to toFixed(2). This makes it hard to edit the fields.
We use angular 1.2.25

You could use a small trick with a condition.
For instance :
$scope.watchActivated = true;
$scope.$watch('objlist', function(newValue, oldValue) {
if ( $scope.watchActivated ) {
$scope.watchActivated = false;
$scope.counter += 1;
for (var count = 0; count < newValue.length; ++count) {
if (typeof newValue[count] != "undefined" && (typeof oldValue == "undefined" || newValue[count].value1 != oldValue[count].value1) )
{
newValue[count].value3 = newValue[count].value1 * newValue[count].value2;
newValue[count].value3 = Number(newValue[count].value3).toFixed(2);
}
if (typeof newValue[count] != "undefined" && (typeof oldValue == "undefined" || newValue[count].value3 != oldValue[count].value3) )
{
newValue[count].value1 = newValue[count].value3 / newValue[count].value2;
newValue[count].value1 = Number(newValue[count].value1).toFixed(2);
}
}
$scope.watchActivated = true;
}
}, true);
Far from elegant but it should work.
Careful the code might not be good I just did a quick edit.

Related

Flutter/Dart Disable Multiple Week Days using enabledDayPredicate of Calendar API / TableCalendar package

At this point, I'm spinning my wheels, but going nowhere and could use some help. I have an array/List of weekdays that I want to disable on my calendar using the enabledPredicateDay function. for example ['sunday', 'monday', 'tuesday'].
return TableCalendar(
calendarBuilders: CalendarBuilders(dowBuilder: (context, day) {
if (day.weekday == DateTime.sunday) {
final text = DateFormat.E().format(day);
return Center(
child: Text(
text,
style: TextStyle(color: Colors.red),
),
);
}
}),
firstDay: kFirstDay,
lastDay: kLastDay,
focusedDay: _focusedDay,
calendarFormat: _calendarFormat,
enabledDayPredicate: (date) {
// this is where we disable any days that the user is not available OR is booked up
var disabledDays = "";
unavailableDays.asMap().forEach((index, value) {
if (index == 0) {
disabledDays = disabledDays + "date.weekday != DateTime.$value";
} else {
disabledDays = disabledDays + " && date.weekday != DateTime.$value";
}
});
date.weekday != disabledDays; // here I'm trying to get some sort of boolean back.
return date.weekday != disabledDays;
}
The problem I'm running into is that I can either only return one day programmatically, let's say in a 'for in' loop, or I need to hardcode it. This is because the return value needs to be a boolean.
I tried combining everything into a string and then converting it to a method so that each day I need disabled can be the return statement like this:
return date.weekday != DateTime.$value && date.weekday != DateTime.$value && date.weekday != DateTime.$value
Everything works fine if I hardcode it like this:
return date.weekday != DateTime.sunday && date.weekday != DateTime.monday && date.weekday != DateTime.tuesday
But I haven't been able to get to this point because I'm getting a string back, but I need a bool.
How do I return multiple days to this particular function?
I figured it out...seems very hacky and maybe this can be improved. What I did here was instantiated a variable for each day. And then, as I go through the weekdays to check which is unavailable with conditional statements, I assign the weekday to the variable if and only if it's unavailable.
var unavailableDay1;
var unavailableDay2;
var unavailableDay3;
var unavailableDay4;
var unavailableDay5;
var unavailableDay6;
var unavailableDay7;
for (var day in daysOfWeek) {
// print(widget.data[day]);
if (widget.data[day] == null) {
unavailableDays.add(day);
}
}
for (var day in unavailableDays) {
if (day == "monday") {
unavailableDay1 = 1;
} else if (day == "tuesday") {
unavailableDay2 = 2;
} else if (day == "wednesday") {
unavailableDay3 = 3;
} else if (day == "thursday") {
unavailableDay4 = 4;
} else if (day == "friday") {
unavailableDay5 = 5;
} else if (day == "saturday") {
unavailableDay6 = 6;
} else if (day == "sunday") {
unavailableDay7 = 7;
}
}
Finally, I check if each of the 7 days has a value, if not null is returned. Thus, it gives me back only days that are enabled! I hope this helps someone! Please help me improve this!
enabledDayPredicate: (date) {
// this is where we disable any days that the user is not available OR is booked up
return date.weekday != unavailableDay1 &&
date.weekday != unavailableDay2 &&
date.weekday != unavailableDay3 &&
date.weekday != unavailableDay4 &&
date.weekday != unavailableDay5 &&
date.weekday != unavailableDay6 &&
date.weekday != unavailableDay7;
},

Getting Cannot read property 'indexOf' of null Custom Filter for search in angularjs

I am using custom filter for my table content search my custom filter function is
return function(data, search) {
if(angular.isDefined(search)) {
var results = [];
var i;
var searchVal = $filter('lowercase')(search);
for(i = 0; i < data.length; i++){
var name = $filter('lowercase')(data[i].name);
var description = $filter('lowercase')(data[i].description);
if(name.indexOf(searchVal) > -1 || description.indexOf(searchVal) > -1){
results.push(data[i]);
}
}
return results;
} else {
return data;
}
};
when i put any text in search box it will get
TypeError: Cannot read property 'indexOf' of null
if((name !=null && name.indexOf(searchVal) > -1) || (description!=null && description.indexOf(searchVal) > -1)){
results.push(data[i]);
}
name or description is giving null value try above code
Check null condition
return function(data, search) {
if(angular.isDefined(search)) {
var results = [];
var i;
var searchVal = $filter('lowercase')(search);
for(i = 0; i < data.length; i++){
var name = $filter('lowercase')(data[i].name);
var description = $filter('lowercase')(data[i].description);
if(name !== null && description !== null){
if(name.indexOf(searchVal) > -1 || description.indexOf(searchVal) > -1){
results.push(data[i]);
}
}
}
return results;
} else {
return data;
}
};

Equivalent of angular.equals in angular2

I am working on migration of angular 1 project to angular 2 . In angular 1 project I was using angular.equals for object comparison angular.equals($ctrl.obj1, $ctrl.newObj); , I searched online for equivalent method in angular 2 but could not find any matching result.
#Günter Yes you are right there is no equivalent in angular2 . While searching more I found third party library lodash which will do same job as angular.equals and syntax is same as angular one and this library solves my problem
Code example from lodash documentation
var object = { 'a': 1 };
var other = { 'a': 1 };
_.isEqual(object, other);
// => true
object === other;
// => false
I rewrote Ariels answer (thank you!) to be TSLINT-friendly. You can also save some continues by using else if, but I think this is more clear. Maybe someone else needs it too:
export function deepEquals(x, y) {
if (x === y) {
return true; // if both x and y are null or undefined and exactly the same
} else if (!(x instanceof Object) || !(y instanceof Object)) {
return false; // if they are not strictly equal, they both need to be Objects
} else if (x.constructor !== y.constructor) {
// they must have the exact same prototype chain, the closest we can do is
// test their constructor.
return false;
} else {
for (const p in x) {
if (!x.hasOwnProperty(p)) {
continue; // other properties were tested using x.constructor === y.constructor
}
if (!y.hasOwnProperty(p)) {
return false; // allows to compare x[ p ] and y[ p ] when set to undefined
}
if (x[p] === y[p]) {
continue; // if they have the same strict value or identity then they are equal
}
if (typeof (x[p]) !== 'object') {
return false; // Numbers, Strings, Functions, Booleans must be strictly equal
}
if (!deepEquals(x[p], y[p])) {
return false;
}
}
for (const p in y) {
if (y.hasOwnProperty(p) && !x.hasOwnProperty(p)) {
return false;
}
}
return true;
}
}
Instead of writing a function to iterate through the objects, you could just use JSON.stringify and compare the two strings?
Example:
var obj1 = {
title: 'title1',
tags: []
}
var obj2 = {
title: 'title1',
tags: ['r']
}
console.log(JSON.stringify(obj1));
console.log(JSON.stringify(obj2));
console.log(JSON.stringify(obj1) === JSON.stringify(obj2));
In Angular 2 you should use pure JavaScript/TypeScript for that so you can add this method to some service
private static equals(x, y) {
if (x === y)
return true;
// if both x and y are null or undefined and exactly the same
if (!(x instanceof Object) || !(y instanceof Object))
return false;
// if they are not strictly equal, they both need to be Objects
if (x.constructor !== y.constructor)
return false;
// they must have the exact same prototype chain, the closest we can do is
// test there constructor.
let p;
for (p in x) {
if (!x.hasOwnProperty(p))
continue;
// other properties were tested using x.constructor === y.constructor
if (!y.hasOwnProperty(p))
return false;
// allows to compare x[ p ] and y[ p ] when set to undefined
if (x[p] === y[p])
continue;
// if they have the same strict value or identity then they are equal
if (typeof (x[p]) !== "object")
return false;
// Numbers, Strings, Functions, Booleans must be strictly equal
if (!RXBox.equals(x[p], y[p]))
return false;
}
for (p in y) {
if (y.hasOwnProperty(p) && !x.hasOwnProperty(p))
return false;
}
return true;
}
You could just copy the original source code from angularjs for the angular.equals function. Usage: equals(obj1, obj2);
var toString = Object.prototype.toString;
function isDefined(value) {return typeof value !== 'undefined';}
function isFunction(value) {return typeof value === 'function';}
function createMap() {
return Object.create(null);
}
function isWindow(obj) {
return obj && obj.window === obj;
}
function isScope(obj) {
return obj && obj.$evalAsync && obj.$watch;
}
function isRegExp(value) {
return toString.call(value) === '[object RegExp]';
}
function simpleCompare(a, b) { return a === b || (a !== a && b !== b); }
function isDate(value) {
return toString.call(value) === '[object Date]';
}
function isArray(arr) {
return Array.isArray(arr) || arr instanceof Array;
}
function equals(o1, o2) {
if (o1 === o2) return true;
if (o1 === null || o2 === null) return false;
// eslint-disable-next-line no-self-compare
if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
if (t1 === t2 && t1 === 'object') {
if (isArray(o1)) {
if (!isArray(o2)) return false;
if ((length = o1.length) === o2.length) {
for (key = 0; key < length; key++) {
if (!equals(o1[key], o2[key])) return false;
}
return true;
}
} else if (isDate(o1)) {
if (!isDate(o2)) return false;
return simpleCompare(o1.getTime(), o2.getTime());
} else if (isRegExp(o1)) {
if (!isRegExp(o2)) return false;
return o1.toString() === o2.toString();
} else {
if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
keySet = createMap();
for (key in o1) {
if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
if (!equals(o1[key], o2[key])) return false;
keySet[key] = true;
}
for (key in o2) {
if (!(key in keySet) &&
key.charAt(0) !== '$' &&
isDefined(o2[key]) &&
!isFunction(o2[key])) return false;
}
return true;
}
}
return false;
}
a = { name: 'me' }
b = { name: 'me' }
a == b // false
a === b // false
JSON.stringify(a) == JSON.stringify(b) // true
JSON.stringify(a) === JSON.stringify(b) // true

Update value from inputText

I'm working with ADF BC and I have several inputTexts.
Let's say I have the folowing scenario:
Step 1: inserting 1, 2, 3 in three different inputTexts (it1, it2 and it3, all three with autoSubmit == true).
Step 2: Click a button who calls the following method:
public String aplicarFiltro() {
Object it1param = null, it2param = null, it3param = null, sos1param = null;
Parametros_IndicadoresLoadAll pila = Parametros_IndicadoresLoadAll.getInstance();
pila.clear();
if(it1.getValue() == null || it1.getValue().toString().isEmpty()) {
it1param = "";
} else {
it1param = it1.getValue();
if(it2.getValue() == null || it2.getValue().toString().isEmpty()) {
it2param = "";
} else {
it2param = it2.getValue();
if(it3.getValue() == null || it3.getValue().toString().isEmpty()) {
it3param = "";
} else {
it3param = it3.getValue();
}
}
}
if(sos1.getValue() != null) {
sos1param = sos1.getValue();
}
pila.init(it1param, it2param, it3param, sos1param);
if (it1.getValue() == null || it1.getValue().toString().isEmpty()) {
showPopup(p1, true);
/* } else if (sos3.getValue() == null) {
showPopup(p2, true); */
}
return null;
}
Step 3: I erase the values from it2 and it3, I click the button again and call the same method. However, the value from it2 and it3 stays the same.
Why does this happen and how can I fix it?
Try to re-think your approach: instead of doing the business in backing beans, try to use BC layer. So you can move the method
public String aplicarFiltro() {..} into Application Module Impl.
There, programatically get a reference to your VO's current Row and read the attribute's values.
First, test your scenario (your method) from BC Tester. Then, you can expose the method through bindings, and call it from backing beans.
ALso, I would expose the RowImpl class for your VO and put some debug info into setIt1(), setIt2(), setIt3() attributes, to see how the change.
Remember, is always far more simple to manage your business on BC layer than managed beans. Stay away from JSF life cycle.
Don't know if more things are wrong. But you're only setting "i2param" to something other than null if i1 has a value and "i3param" to something other then null if i1 and i2 has a value.
So start with the following. Change this:
if(it1.getValue() == null || it1.getValue().toString().isEmpty()) {
it1param = "";
} else {
it1param = it1.getValue();
if(it2.getValue() == null || it2.getValue().toString().isEmpty()) {
it2param = "";
} else {
it2param = it2.getValue();
if(it3.getValue() == null || it3.getValue().toString().isEmpty()) {
it3param = "";
} else {
it3param = it3.getValue();
}
}
}
to:
if(it1.getValue() == null || it1.getValue().toString().isEmpty()) {
it1param = "";
} else {
it1param = it1.getValue();
}
if(it2.getValue() == null || it2.getValue().toString().isEmpty()) {
it2param = "";
} else {
it2param = it2.getValue();
}
if(it3.getValue() == null || it3.getValue().toString().isEmpty()) {
it3param = "";
} else {
it3param = it3.getValue();
}

how to remove states from stateProvider

After removing the states from $stateProvider and its caches from cacheTemplate,it gives me a 'already defined' error when trying to add the same state name.
clearStates: function () {
var states = this.$state.get();
for (var i = 0; i < states.length; i++) {
if (states[i].name != 'shell.error404' &&
states[i].name != 'shell.error500' &&
states[i].name != 'shell' &&
states[i].name != '') {
var tmplUrl = states[i].templateUrl;
if (tmplUrl) {
this.templateCache.remove(tmplUrl);
}
delete states[i];
}
}
}
any way to do that ?
Try
clearStates: function () {
var states = this.$state.get();
var itemsToBeRemoved = [];
var removalIndex = 0;
for (var i = 0; i < states.length; i++) {
if (states[i].name != 'shell.error404' &&
states[i].name != 'shell.error500' &&
states[i].name != 'shell' &&
states[i].name != '') {
var tmplUrl = states[i].templateUrl;
if (tmplUrl) {
this.templateCache.remove(tmplUrl);
}
//delete states[i];
itemsToBeRemoved[removalIndex++] = i;
}
}
for(var j=0;j<itemsToBeRemoved.length;j++){
states.splice(itemsToBeRemoved[j],1);
}
}
Store the index(s) to be deleted and use states.splice(>index<,1) instead of delete states[i]
delete leaves an empty element in the array at the given index, this may be the cause of your issue.

Resources