I'm trying to get value from DynamoDB then assign the value to ng-model to display the value. However, the data is always null.
Dynamodb table
"meta_value": {
"clause_note": "Note: good job!",
"show_clause_note": true,
"shown": true
},
I'm getting the clause_note
Controller
$scope.clause_note = null;
$scope.item.remark = null;
$scope.loading = true;
$scope.getSettings = function () {
customPrint.getAllSettings($scope.module).then(function (res) {
if ($scope.module) {
settings.then(function (stt) {
$scope.clause_note = stt['clause_note'];
});
} else {
alert('No module is specified!');
}
}).finally(function () {
if ($scope.item.remark === $scope.clause_note) {
$scope.item.remark = '';
console.log($scope.clause_note);
}
else
{
$scope.clause_note = {show_clause_note: true};
$scope.clause_note = {shown: true};
}
});
};
$scope.getSettings();
The console log returned as null.
html
<ng-quill-editor ng-model="item.remark"></ng-quill-editor>
There isn't really enough information to answer this question. What is the value of the stt variable? If meta_value is a property on that object then this line:
$scope.clause_note = stt['clause_note'];
should be changed to
$scope.clause_note = stt.meta_value.clause_note
I'll edit this answer if you can let me know :)
But there are other problems with the code that make it harder to maintain.
For instance, it seems that $scope.clause_note can be a string or an object. That makes it harder to work with in other parts of the code because it's not always obvious what type it is.
The settings promise seems to come from nowhere. Maybe it would be a good idea to show where that comes from in your question. Also the response from getAllSettings is not used here. Is that a mistake?
Perhaps you should check if $scope.module exists before you even send the getAllSettings request. If it doesn't alert, and return. That should remove any branching logic inside your promise callbacks.
Related
How do I get array form data using busboy?
In route:
req.busboy.on('field', function(fieldname, val){
//fieldname is string, expecting array
//'bunnies[gray]', etc...
});
And my view:
form(method="post" action="/post/path" enctype="multipart/form-data")
input(name="bunnies[gray]")
input(name="bunnies[white]")
input(name="bunnies[black]")
input(name="bunnies[brown]")
input(name="bunnies[purple]")
So busboy isn't stupid -- multipart/form-data does not by default support arrays in the same way as a JSON body does.
Requests with arrayName[n] as field names will not be parsed as arrays by busboy alone -- such a payload will have still have to be parsed manually.
One can manually parse these array values using one of these other answers...
... but if manually parsing arrays is undesired, one may consider using co-busboy instead using this option:
autoFields: true
The question is rather old, but in case someone else stumbles upon this problem, here's what I did:
var arr = new Array();
req.pipe(req.busboy);
req.busboy.on('field', function(key, value) {
if(key === 'array_name[]') {
arr.push(value);
}
});
req.busboy.on('finish', function() {
console.log(arr);
});
Question if 5 years old but it gave me a hint. I am coming from PHP background and didn't realize that Busboy is this stupid, so if you want to process array of fields, you need to actually process them like this:
busboy.on('field', (fieldname, val) => {
if (fieldname.indexOf('[]') !== -1) {
let fn = fieldname.replace('[]', '');
if (typeof req.body[fn] === 'undefined') {
req.body[fn] = [];
}
req.body[fn].push(val);
} else {
req.body[fieldname] = val;
}
});
Hope to save someone else a few hours of debugging ...
I'm using the Angular-Leaflet directive to display a heatmap, and I want the data to evolve through time. My code looks like:
getData().then(function (data) {
$scope.heat.index = 0;
$scope.heat.data = data;
$scope.layers.overlays.heat = {
name: "Heatmap",
type: "heat",
data: $scope.heat.data[$scope.heat.index], // data is a dictionary, not an array
visible: true
};
$scope.$watch('heat.index', function (new_index) {
$scope.layers.overlays.heat.data = $scope.heat.data[new_index];
});
});
However, when I change data.index (through a slider), nothing happens. What could be going on? I know that Angular-Leaflet supports this behavior because of this Github issue where someone added it.
leafletData.getMap().then(function (map) {
map.eachLayer(function (layer) {
if (layer.options.layerName == 'heatmap') {
layer.setLatLngs(newHeatmapData);
}
})
})
This worked for me.
Leaflet.heat provides a redraw() method but that didn't work for me.
I been trying to do checkbox Checkall and UnCheckall using subscribe and i'm partially successful doing that but i am unable to find a fix in couple of scenarios when i am dealing with subscribe .
Using subscribe :
I am here able to checkAll uncheckAll but when i uncheck a child checkbox i.e test1 or test2 i need my parent checkbox name also to be unchecked and in next turn if i check test1 the parent checkbox should be checked i.e keeping condition both child checkboxes are checked .
For fiddle : Click Here
ViewModel :
self.selectedAllBox.subscribe(function (newValue) {
if (newValue == true) {
ko.utils.arrayForEach(self.People(), function (item) {
item.sel(true);
});
} else {
ko.utils.arrayForEach(self.People(), function (item) {
item.sel(false);
});
}
});
The same scenario can be done perfectly in easy way using computed but due some performance issues i need to use subscribe which is best way it wont fire like computed onload .
Reference : Using computed same thing is done perfectly check this Fiddle
I tried to use change event in individual checkbox binding but its a dead end till now.
Any help is appreciated .
Your subscription only applies to edits on the selectedAllBox. To do what you want, you'll need subscriptions on every Person checkbox as well, to check for the right conditions and uncheck the selectedAllBox in the right situations there.
It strikes me as odd that this would be acceptable but using computed() is not. Maybe you should reconsider that part of your answer. I would much rather compute a "isAllSelected" value based on my viewModel state, then bind the selectedAllBox to that.
I solved a similar problem in my own application a couple of years ago using manual subscriptions. Although the computed observable method is concise and easy to understand, it suffers from poor performance when there's a large number of items. Hopefully the code below speaks for itself:
function unsetCount(array, propName) {
// When an item is added to the array, set up a manual subscription
function addItem(item) {
var previousValue = !!item[propName]();
item[propName]._unsetSubscription = item[propName].subscribe(function (latestValue) {
latestValue = !!latestValue;
if (latestValue !== previousValue) {
previousValue = latestValue;
unsetCount(unsetCount() + (latestValue ? -1 : 1));
}
});
return previousValue;
}
// When an item is removed from the array, dispose the subscription
function removeItem(item) {
item[propName]._unsetSubscription.dispose();
return !!item[propName]();
}
// Initialize
var tempUnsetCount = 0;
ko.utils.arrayForEach(array(), function (item) {
if (!addItem(item)) {
tempUnsetCount++;
}
});
var unsetCount = ko.observable(tempUnsetCount);
// Subscribe to array changes
array.subscribe(function (changes) {
var tempUnsetCount = unsetCount();
ko.utils.arrayForEach(changes, function (change) {
if (change.moved === undefined) {
if (change.status === 'added') {
if (!addItem(change.value))
tempUnsetCount++;
} else {
if (!removeItem(change.value))
tempUnsetCount--;
}
}
});
unsetCount(tempUnsetCount);
}, null, 'arrayChange');
return unsetCount;
}
You'll still use a computed observable in your viewmodel for the the select-all value, but now it'll only need to check the unselected count:
self.unselectedPeopleCount = unsetCount(self.People, 'Selected');
self.SelectAll = ko.pureComputed({
read: function() {
return self.People().length && self.unselectedPeopleCount() === 0;
},
write: function(value) {
ko.utils.arrayForEach(self.People(), function (person) {
person.Selected(value);
});
}
}).extend({rateLimit:0});
Example: http://jsfiddle.net/mbest/dwnv81j0/
The computed approach is the right way to do this. You can improve some performance issues by using pureComputed and by using rateLimit. Both require more recent versions of Knockout than the 2.2.1 used in your example (3.2 and 3.1, respectively).
self.SelectAll = ko.pureComputed({
read: function() {
var item = ko.utils.arrayFirst(self.People(), function(item) {
return !item.Selected();
});
return item == null;
},
write: function(value) {
ko.utils.arrayForEach(self.People(), function (person) {
person.Selected(value);
});
}
}).extend({rateLimit:1});
http://jsfiddle.net/mbest/AneL9/98/
After upgrading to 1.2, promises returned by my services behave differently...
Simple service myDates:
getDates: function () {
var deferred = $q.defer();
$http.get(aGoodURL).
success(function (data, status, headers, config) {
deferred.resolve(data); // we get to here fine.
})......
In earlier version I could just do, in my controller:
$scope.theDates = myDates.getDates();
and the promises returned from getDates could be bound directly to a Select element.
Now this doesn't work and I'm forced to supply a callback on the promise in my controller or the data wont bind:
$scope.theDates = matchDates.getDates();
$scope.theDates.then(function (data) {
$scope.theDates = data; // this wasn't necessary in the past
The docs still say:
$q promises are recognized by the templating engine in angular, which means that in templates you can treat promises attached to a scope as if they were the resulting values.
They (promises) were working in older versions of Angular but in the 1.2 RC3 automatic binding fails in all my simple services.... any ideas on what I might be doing wrong.
There are changes in 1.2.0-rc3, including one you mentioned:
AngularJS 1.2.0-rc3 ferocious-twitch fixes a number of high priority
issues in $compile and $animate and paves the way for 1.2.
This release also introduces some important breaking changes that in some cases could break your directives and templates. Please
be sure to read the changelog to understand these changes and learn
how to migrate your code if needed.
For full details in this release, see the changelog.
There is description in change log:
$parse:
due to 5dc35b52, $parse and templates in general will no longer automatically unwrap promises. This feature has been deprecated and
if absolutely needed, it can be reenabled during transitional period
via $parseProvider.unwrapPromises(true) api.
due to b6a37d11, feature added in rc.2 that unwraps return values from functions if the values are promises (if promise unwrapping is
enabled - see previous point), was reverted due to breaking a popular
usage pattern.
As #Nenad notices, promises are no longer automatically dereferenced. This is one of the most bizarre decisions I've ever seen since it silently removes a function that I relied on (and that was one of the unique selling points of angular for me, less is more). So it took me quite a bit of time to figure this out. Especially since the $resource framework still seems to work fine. On top of this all, this is also a release candidate. If they really had to deprecate this (the arguments sound very feeble) they could at least have given a grace period where there were warnings before they silently shut it off. Though usually very impressed with angular, this is a big minus. I would not be surprised if this actually will be reverted, though there seems to be relatively little outcry so far.
Anyway. What are the solutions?
Always use then(), and assign the $scope in the then method
function Ctrl($scope) {
foo().then( function(d) { $scope.d = d; });
)
call the value through an unwrap function. This function returns a field in the promise and sets this field through the then method. It will therefore be undefined as long as the promise is not resolved.
$rootScope.unwrap = function (v) {
if (v && v.then) {
var p = v;
if (!('$$v' in v)) {
p.$$v = undefined;
p.then(function(val) { p.$$v = val; });
}
v = v.$$v;
}
return v;
};
You can now call it:
Hello {{ unwrap(world) }}.
This is from http://plnkr.co/edit/Fn7z3g?p=preview which does not have a name associated with it.
Set $parseProvider.unwrapPromises(true) and live with the messages, which you could turn off with $parseProvider.logPromiseWarnings(false) but it is better to be aware that they might remove the functionality in a following release.
Sigh, 40 years Smalltalk had the become message that allowed you to switch object references. Promises as they could have been ...
UPDATE:
After changing my application I found a general pattern that worked quite well.
Assuming I need object 'x' and there is some way to get this object remotely. I will then first check a cache for 'x'. If there is an object, I return it. If no such object exists, I create an actual empty object. Unfortunately, this requires you to know if this is will be an Array or a hash/object. I put this object in the cache so future calls can use it. I then start the remote call and on the callback I copy the data obtained from the remote system in the created object. The cache ensures that repeated calls to the get method are not creating lots of remote calls for the same object.
function getX() {
var x = cache.get('x');
if ( x == undefined) {
cache.put('x', x={});
remote.getX().then( function(d) { angular.copy(d,x); } );
}
return x;
}
Yet another alternative is to provide the get method with the destination of the object:
function getX(scope,name) {
remote.getX().then( function(d) {
scope[name] = d;
} );
}
You could always create a Common angular service and put an unwrap method in there that sort of recreates how the old promises worked. Here is an example method:
var shared = angular.module("shared");
shared.service("Common", [
function () {
// [Unwrap] will return a value to the scope which is automatially updated. For example,
// you can pass the second argument an ng-resource call or promise, and when the result comes back
// it will update the first argument. You can also pass a function that returns an ng-resource or
// promise and it will extend the first argument to contain a new "load()" method which can make the
// call again. The first argument should either be an object (like {}) or an array (like []) based on
// the expected return value of the promise.
// Usage: $scope.reminders = Common.unwrap([], Reminders.query().$promise);
// Usage: $scope.reminders = Common.unwrap([], Reminders.query());
// Usage: $scope.reminders = Common.unwrap([], function() { return Reminders.query(); });
// Usage: $scope.reminders.load();
this.unwrap = function(result, func) {
if (!result || !func) return result;
var then = function(promise) {
//see if they sent a resource
if ('$promise' in promise) {
promise.$promise.then(update);
}
//see if they sent a promise directly
else if ('then' in promise) {
promise.then(update);
}
};
var update = function(data) {
if ($.isArray(result)) {
//clear result list
result.length = 0;
//populate result list with data
$.each(data, function(i, item) {
result.push(item);
});
} else {
//clear result object
for (var prop in result) {
if (prop !== 'load') delete result[prop];
}
//deep populate result object from data
$.extend(true, result, data);
}
};
//see if they sent a function that returns a promise, or a promise itself
if ($.isFunction(func)) {
// create load event for reuse
result.load = function() {
then(func());
};
result.load();
} else {
then(func);
}
return result;
};
}
]);
This basically works how the old promises did and auto-resolves. However, if the second argument is a function it has the added benefit of adding a ".load()" method which can reload the value into the scope.
angular.module('site').controller("homeController", function(Common) {
$scope.reminders = Common.unwrap([], Reminders.query().$promise);
$scope.reminders = Common.unwrap([], Reminders.query());
$scope.reminders = Common.unwrap([], function() { return Reminders.query(); });
function refresh() {
$scope.reminders.load();
}
});
These were some good answers, and helped me find my issue when I upgraded angular and my auto-unwrapping of promises stopped working.
At the risk of being redundant with Peter Kriens, I have found this pattern to work for me (this is a simple example of simply putting a number of famous people's quotes onto a page).
My Controller:
angular.module('myModuleName').controller('welcomeController',
function ($scope, myDataServiceUsingResourceOrHttp) {
myDataServiceUsingResourceOrHttp.getQuotes(3).then(function (quotes) { $scope.quotes = quotes; });
}
);
My Page:
...
<div class="main-content" ng-controller="welcomeController">
...
<div class="widget-main">
<div class="row" ng-repeat="quote in quotes">
<div class="col-xs-12">
<blockquote class="pull-right">
<p>{{quote.text}}</p>
<small>{{quote.source}}</small>
</blockquote>
</div>
</div>
</div>
...
i'm trying to filter a collection which has models with some nested object. Unfortunately, my result are always empty.
So my models returned in the collection are build like this:
My goal is simple:
I have a view with a list of tag and a content view with all the questions. When a user click on tag, for example, "c#", i want to filter my collection to just return questions with tag "c#"
Before i was doing a fetch on my server and it was working fine, but it was not optimize.
I already have a collection with all the questions so why make a new call, a filter is a better solution i think.
But i didn't succeded with my filter and i don't know if it's possible to do. For now i put my filter in my router because it's more easy to test.
i can't make a filter like this because i have an array of object
getQuestionsByTags: function(query) {
var test = this.questionsCollection.filter(function(model) {
return model.attributes.tags.name == query;
})
console.log('result');
console.log(test);
},
So i was thinking to make a loop but my result is always an empty array.
getQuestionsByTags: function(query) {
var test = this.questionsCollection.filter(function(model) {
_.each(model.attributes.tags, function(tag) {
return tag.name == query;
})
})
console.log('result');
console.log(test);
},
It's maybe simple, but i don't know what to do.
Thanks in advance :)
i've just found a solution that work.
getQuestionsByTags: function(query) {
var flag;
var test2 = this.questionsCollection.filter(function(model) {
flag = false;
_.each(model.attributes.tags, function(tag) {
if(tag.name == query) {
flag = true;
}
})
if(flag) {
return model.attributes;
}
})
console.log('result');
console.log(test2);
},
i put a flag. If he turn true inside the loop, the model has this tag so i return it.
I think it's not very conventional, so if someone have another solution, feel free to post it :)