how to differentiate user typed their own value or selected a suggestion from typeahead - typeahead

I am using typeahead.js.
var getname = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('CompanyName'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: '/Profile/Getname?searchText=%QUERY',
});
getname.initialize();
var $emp = $('#employment');
$emp.typeahead(null, {
name: 'CompanyNames',
displayKey: 'CompanyName',
source: getname.ttAdapter(),
});
$emp.on("typeahead:selected", function (obj, user) {
$("#UserId").val(user.UserID);
}
is there a way to know when the user selects an option from the list or typed their own value?

I made it that way
var voivodeshipSelected = false;
$('input[name=voivodeshipSelect].typeahead').on('typeahead:select', function (ev, suggestion) {
$(this).validationEngine('hide');
voivodeshipSelected = true;
});
$('input[name=voivodeshipSelect].typeahead').on('typeahead:change', function (ev, data) {
if (!voivodeshipSelected) {
$(this).validationEngine('showPrompt', 'choose voivodeship', 'error', 'topRight', true);
}
else {
voivodeshipSelected = false;
}
});
I just add global variable which is set on select so than on change which is binded when select, check it, and showing prompt or not.

Related

why test coverage is not 100%

I wrote a method which returns true if there are folders left in the modal to be added and return false if there are no folders left in the modal to be added to the application
my method in angular/typesrcipt
ifAllFoldersHaveBeenAdded() {
let added = false;
let folderToExclude = find(this.bdDataModel.lenderDefinedFolders, {
name: 'Correspondence' });
let foldersToBeChecked = without(this.bdDataModel.lenderDefinedFolders, folderToExclude);
for (let i = 0; i < foldersToBeChecked.length; i++) {
let folderPresent = find(this.bdDataModel.folders, { name: foldersToBeChecked[i].name });
if (folderPresent) {
added = true;
} else {
added = false;
return added;
}
}
return added;
}
my test...
describe('ifAllFoldersHaveBeenAdded()', () => {
it('returns false if there are folders left in the modal to be added', () => {
let added = false;
$ctrl.bdDataModel.folders;
$ctrl.foldersToBeChecked = [{ name: 'FMS' }, { name: 'Other' }];
$ctrl.folderPresent = { name: 'FMS' };
$ctrl.ifAllFoldersHaveBeenAdded();
added = true;
expect(added).toEqual(true);
});
it('returns true is all folders have been added to the application', () => {
let added = false;
$ctrl.bdDataModel.folders;
$ctrl.foldersToBeChecked = [{ name: 'FMS' }, { name: 'Other' }];
$ctrl.folderPresent = { name: 'LMI' };
$ctrl.ifAllFoldersHaveBeenAdded();
expect(added).toEqual(false);
});
});
Both tests pass but icov coverage report is marking the following lines as uncovered...
find(this.bdDataModel.folders, { name: foldersToBeChecked[i].name });
if (folderPresent) {
added = true;
}
else {
added = false;
return added;
}
please tell what i should add in the test to have a 100% test coverage for this unit test.
thanks in advance
There is so much wrong with your test. First off, you need to get rid of the local added variables completely. Doing something like the following
added = true;
expect(added).toEqual(true);
Is essentially the same as doing expect(true).toBe(true)
Next, the folderPresent and foldersToBeChecked variables are local to the ifAllFoldersHaveBeenAdded function. They are not controller variables. You don't need to set $ctrl.folderPresent or $ctrl.foldersToBeChecked in your test.
You need to define these two variables $ctrl.bdDataModel.lenderDefinedFolders and $ctrl.bdDataModel.folders
Because lenderDefinedFolders is undefined the length of foldersToBeChecked in your function is going to be 0. So the for loop will never execute.
Your test should look something like this:
it('returns false if there are folders left in the modal to be added', () => {
$ctrl.bdDataModel.lenderDefinedFolders = [{ //add lender defined folders here }]
$ctrl.bdDataModel.folders = [{ //add some folders here}]
let added = $ctrl.ifAllFoldersHaveBeenAdded();
expect(added).toEqual(true);
});

Ember - Within action, result is defined, returnvalue of same action logged in parent action is undefined? Why?

Quick and shortly I have following problem:
I have following two actions within a component in Ember:
createData: function(user) {
let collection = [];
for (let i = 0; i < user.posts.length; i++) {
let data = this.send('createSingleData',user.posts[i], user, 'post');
console.log(data);
collection.push(data);
}
return collection;
},
createSingleData: function(data, user, type) {
let entitySkeleton = {
name: data.place.name,
belongsTo: user.id,
position: {
data.place.location.longitude,
data.place.location.latitude
}
};
console.log(entitySkeleton);
return entitySkeleton;
}
the first log - within createSingleData, right before returning the logged value - writes the entitySkeleton as Object into the console - as expected.
However, the console.log(data) - within createData - writes 'undefined' to the console.
Is there any aspect of asynchrounosity I didn't respect?
P.S.:
I also logged any paramater within createSingleData, they are all set properly.
The variable collection also only gets pushed 'undefined'.
You cannot return the value from action, instead you can set property from the action.
how to return values from actions in emberjs
actions: {
PrintSomething: function() {
let obj = [{a: 'raj'}, {a: 'Prudvi'}, {a : 'thimappa'}]
console.log('before', obj);
this.send('returnSomething', obj);
console.log('after calling action', this.get('returnvalue'));
},
returnSomething: function(obj) {
obj.push({a: 'FSDFSDF'})
var data = obj;
this.set('returnvalue', data);
}
}

How to properly setup a store that acts as a single pointer across your web app

I have a home grown store that has a simple identityMap. When I return an array of models from this and bind it to a controllers "model" it reflects what you'd expect
the first time you hit a route it reflects this in the template as
you'd expect
But later if I get this same store instance (it's a singleton) and push an object into the identityMap it doesn't automatically update the previous template
The store itself is super basic (no relationships/ just push objects and get by id)
function buildRecord(type, data, store) {
var containerKey = 'model:' + type;
var factory = store.container.lookupFactory(containerKey);
var record = factory.create(data);
var id = data.id;
identityMapForType(type, store)[id] = record;
return record;
}
function identityMapForType(type, store) {
var typeIdentityMap = store.get('identityMap');
var idIdentityMap = typeIdentityMap[type] || {};
typeIdentityMap[type] = idIdentityMap;
return idIdentityMap;
}
var Store = Ember.Object.extend({
init: function() {
this.set('identityMap', {});
},
push: function(type, data) {
var record = this.getById(type, data.id);
if (record) {
record.setProperties(data);
} else {
record = buildRecord(type, data, this);
}
return record;
},
getById: function(type, id) {
var identityMap = identityMapForType(type, this);
return identityMap[id] || null;
}
getEverything: function(type) {
var identityMap = identityMapForType(type, this);
var keys = Object.keys(identityMap);
var values = [];
for (var i = 0; i < keys.length; i++)
{
var val = identityMap[keys[i]];
values.push(val);
}
return values;
}
});
Ember.onLoad('Ember.Application', function(Application) {
Application.initializer({
name: "store",
initialize: function(container, application) {
application.register('store:main', Store);
application.inject('controller', 'store', 'store:main');
application.inject('route', 'store', 'store:main');
}
});
});
In my model hook (in the find all route lets say) I simply query for each item and push them into the store
//inside my model find method lets say ...
find: function(store) {
var url = "/api/foo";
$.getJSON(url, function(response) {
response.forEach(function(data) {
var model = store.push("foo", data);
}
}
return store.getEverything("foo");
}
So I assumed my controllers' model was this bound array (using a single pointer in memory for this array of models)
Yet when I do this inside a controller submit action it won't re-render that prev view (to show the new item that was added to that store's array)
actions: {
submit: function() {
var foo = {}; // assume this is a real json response or js object
var store = this.get("store");
store.push("foo", foo);
}
}
Because of this today, I'm forced to get the parent controller and "set" / "push" this new object to it's content/model property :(
Anyone know what I'm doing wrong here?
I like homegrown solutions, they generally are easier to work with and meld around what you're working on.
So I'm actually surprised this part is working:
//inside my model find method lets say ...
find: function(store) {
var url = "/api/foo";
$.getJSON(url, function(response) {
response.forEach(function(data) {
var model = store.push("foo", data);
}
}
return store.getEverything("foo");
}
If I read through it I see you make an ajax call, and then return store.getEverything immediately after (without a guarantee that the ajax call has completed). Then inside of getEverything you create a new array called values then iterate the identity map linking up all of the currently available records and return that. At this point your store is unaware of this array going forward. So any changes to your store wouldn't get pushed out to the array, they might make it into the identity map, but it isn't feeding the getEverything array.
There are a couple of solutions, one would be to keep track of your everything array. That collection would be super cheap to build, more expensive to search, so keeping the identity map as well would be super beneficial. You could follow your same pattern, but one collection would be the map, whereas the other would be an array of everything.
Modified Build Record
function buildRecord(type, data, store) {
var containerKey = 'model:' + type;
var factory = store.container.lookupFactory(containerKey);
var record = factory.create(data);
var id = data.id;
identityMapForType(type, store)[id] = record;
everythingArrayForType(type, this).pushObject(record);
return record;
}
Copy paste, possibly could be refactored
function everythingArrayForType(type, store) {
var everythingArrays = store.get('everythingArrays');
var arr = everythingArrays[type] || [];
everythingArrays[type] = arr;
return arr;
}
Slightly modified Store
var Store = Ember.Object.extend({
init: function() {
this.set('identityMap', {});
this.set('everythingArrays', {});
},
push: function(type, data) {
var record = this.getById(type, data.id);
if (record) {
record.setProperties(data);
} else {
record = buildRecord(type, data, this);
}
return record;
},
getById: function(type, id) {
var identityMap = identityMapForType(type, this);
return identityMap[id] || null;
}
getEverything: function(type) {
return everythingArrayForType(type, this);
}
});

nokia here maps geocoding and display map

please, could someone explain me how can I manage, in Here Maps code, nokia.maps.map.Display listener and nokia.places.search.manager.geocode method?
I have markers to be geocoded, in geocode "oncomplete" it waits for the request to be completed, after that it listens when map display is ready, so as it happens asynchronously, it sometimes displays on browser a map not finished yet, this is because map.zoomTo(bbox, false) was not executed.
How can I manage these two events?
<script type="text/javascript">
function goPageOnLoad() {
container = new nokia.maps.map.Container();
map = new nokia.maps.map.Display(document.getElementById('gmapcanvas'),
{ components:[ infoBubbles, new nokia.maps.map.component.Behavior(), new
nokia.maps.map.component.ZoomBar(), new
nokia.maps.map.component.Overview(), new
nokia.maps.map.component.TypeSelector(), new
nokia.maps.map.component.ScaleBar() ] });
addMarkersGeoLoc(map,container);
}
function addMarkersGeoLoc(map,container) {
countMarkerGeoLoc=1; coordinate = new
nokia.maps.geo.Coordinate(0, 0); startGeoCode('Via Roma 2, 16038 Santa
Margherita Ligure GE ');
}
function startGeoCode(addressStringt) {
nokia.places.search.manager.geoCode({
searchTerm : addressString,
onComplete: function(data, requestStatus){
if(data != null){
coordinate =
new nokia.maps.geo.Coordinate(data.location.position.latitude,
data.location.position.longitude);
var marker = new
nokia.maps.map.StandardMarker(coordinate, {brush: {color: "#FF0000"}});
marker.addListener( CLICK, function (evt) {
infoBubbles.openBubble(content, marker.coordinate); } );
container.objects.add(marker);
managersFinished++;
}
else {
managersFinished++; alert('Address: '+addressString+', is not
localizable.');
}
if(managersFinished === countMarkerGeoLoc) {
map.objects.add(container);
map.set('zoomLevel', 14);
map.addListener("displayready", function () {
map.set('center',
[40.645304, 14.874063]);
bbox = container.getBoundingBox();
if(bbox !=null){
map.zoomTo(bbox, false);
}
});
}
}
});
}
</script>
The simplest method would be to wait for the displayready event before starting your geocoding.
function goPageOnLoad() {
container = new nokia.maps.map.Container();
map = new nokia.maps.map.Display
.. etc...
map.addListener('displayready', function () {
addMarkersGeoLoc(map,container);
}, false);
The other alternative would be to have a global bbox variable and use zoomTo() twice - either on displayready or on managersFinished === countMarkerGeoLoc i.e.
var bbox;
...
function goPageOnLoad() {
container = new nokia.maps.map.Container();
map = new nokia.maps.map.Display
.. etc...
map.addListener("displayready", function () {
if(bbox){map.zoomTo(bbox, false);}
});
...
if(managersFinished === countMarkerGeoLoc) {
map.objects.add(container);
bbox = container.getBoundingBox();
map.zoomTo(bbox, false);
Either the first or the second of the zoomTo() functions must fire to move the map.

how to return values from actions in emberjs

how to return some value from actions??
I tried this:
var t = this.send("someAction", params);
...
actions:{
someAction: function(){
return "someValue";
}
}
actions don't return values, only true/false/undefined to allow bubbling. define a function.
Ember code:
send: function(actionName) {
var args = [].slice.call(arguments, 1), target;
if (this._actions && this._actions[actionName]) {
if (this._actions[actionName].apply(this, args) === true) {
// handler returned true, so this action will bubble
} else {
return;
}
} else if (this.deprecatedSend && this.deprecatedSendHandles && this.deprecatedSendHandles(actionName)) {
if (this.deprecatedSend.apply(this, [].slice.call(arguments)) === true) {
// handler return true, so this action will bubble
} else {
return;
}
}
if (target = get(this, 'target')) {
Ember.assert("The `target` for " + this + " (" + target + ") does not have a `send` method", typeof target.send === 'function');
target.send.apply(target, arguments);
}
}
I had the same question. My first solution was to have the action put the return value in a certain property, and then get the property value from the calling function.
Now, when I need a return value from an action, I define the function that should be able to return a value seperately, and use it in an action if needed.
App.Controller = Ember.Controller.extend({
functionToReturnValue: function(param1, param2) {
// do some calculation
return value;
},
});
If you need the value from the same controller:
var value = this.get("functionToReturnValue").call(this, param1, param2);
From another controller:
var controller = this.get("controller"); // from view, [needs] or whatever
var value = controller.get("functionToReturnValue").call(controller, param1, param2); // from other controller
The first argument of the call() method needs to be the same object that you are running the return function of; it sets the context for the this reference. Otherwise the function will be retrieved from the object and ran from the current this context. By defining value-returning functions like so, you can make models do nice stuff.
Update I just found this function in the API that seems to do exactly this: http://emberjs.com/api/#method_tryInvoke
Look this example:
let t = this.actions.someAction.call(this, params);
Try
var t = this.send("someAction", params);
instead of
vat r = this.send("someAction", params);
Just use #set for set value which you want to return
actions:{
someAction: function(){
// return "someValue";
this.set('var', someValue);
}
}