Saving Breeze entities manually and updating keyMappings - javascript

I want to manually save entities in Breeze. We just don't have the option (as much as I try to fight for my opinion) to use the SaveChanges(JObject saveBundle) and need to directly hit a 3rd party Web API with a specific URL for POST/PUT requests.
So I am basically looping through EntityManager.getChanges() and then handling Modified, Added, and Deleted entities.
I can handle the "Modified" without any problems. However, on "Added", I know I need to update keyMappings when I add a new entity after successful save but cannot find any documentation on how to do that manually in JavaScript.
I also wanted to see if there any examples in returning any errors. Basically I want to hook into this call:
$http(params).then(
function (response) { // success
console.log(response);
// update key mappings if its an "Added" somehow
// entityAspect.acceptChanges();
dfd.resolve("something eventually");
},
function () { // error
// added error object here and reject changes on this entity? or just show error message?
dfd.reject("error");
});
return dfd.promise;

In case anyone's wondering, I just check the entityAspect.entityState.isAdded() method. Get the new identity returned from my 3rd party and just update the id accordingly. Our system is a little bit nicer in that we have a set key for all of the entities.
Code wise it looks something like this (dfd is a $q defer):
$http(params).then(function (response) { // success
// on add update the instance id with the new instance id
if (entityState.isAdded()) {
var newId = response.data.changedInstance.newId;
entity.Id = newId ;
}
entityAspect.acceptChanges();
dfd.resolve(response.data);
},
function (response) { // error
dfd.reject(response.data);
});

Related

Get an entityName by GUID, despite of what form is loaded at the moment for use in XrmServiceToolkit.Soap.setState()

I'm stuck on the XrmServiceToolkit.Soap.setState() function.
Prerequisites
I'm on studying MS CRM. One of my tasks is to activate and deactivate a record (this time it's a native "contact" record). I've decided to build my solution in a following way (according to other tasks):
On the OnLoad event of my custom entity's form I create a new contact using XrmServiceToolkit (task condition), then update one field in newly created contact. This actually doesn't make sense in production to create something on this event, but nevertheless, is done this way only for my convenience:
function Practice3()
{
let entityToUpdate = CreateRecordWithToolkit("VP_Created by","Xrm Service Toolkit","4F52999B-0E63-EA11-8125-00155D06F203");
alert("Switching to new record!");
Xrm.Utility.openEntityForm("contact", entityToUpdate);
UpdateFieldsWithXrmServiceToolkit(entityToUpdate);
DeactivateAndActivateContact(entityToUpdate);
}
// I don't post the CreateRecordWithToolkit(fname, lname, accountId) and UpdateFieldsWithXrmServiceToolkit(targetEntity) functions 'cos all is Ok there
// and entityToUpdate GUID is passed properly
Between creation and posting updates I send a command to load that newly created form. It does'n activated it at once, but updates are inserted correctly.
Then I pass the same GUID to my next function DeactivateAndActivateContact(targetEntity) and here I stuck.
Question
Can anyone explain or give a hint on how to use the XrmServiceToolkit.Soap.setState() function? I can't get the "entityName" parameter - what is this? How can I get it with having entity's GUID? I was trying to use it like this:
function DeactivateAndActivateContact(targetEntity)
{
let entityName = GetObjectAttribute(targetEntity, "contact", "name");
XrmServiceToolkit.Soap.setState(entityName,targetEntity, "0", "0",false);
Xrm.Page.data.refresh(true).then(null, null);
}
but getting an undefined error.
Is there any way to get an entityName by GUID? 'cos I'm getting the name of current form.
Error is raised when stepping in to this line:
XrmServiceToolkit.Soap.setState(entityName,targetEntity, "0", "0",false);
To Deactivate contact here is below code,
Note Rest API call is Asynchronous and You will have to use execution context and formcontext in Dynamics
Also you could change your other SOAP calls with Rest API. Refer to CRM Rest Builder, it's way easy to build calls with it.
var entity = {};
entity.statuscode = 2;
entity.statecode = 1;
Xrm.WebApi.online.updateRecord("contact", "4A342F12-D248-E211-8669-005056922461", entity).then(
function success(result) {
var updatedEntityId = result.id;
formContext.data.refresh(yes).then(successCallback, errorCallback);
},
function(error) {
Xrm.Utility.alertDialog(error.message);
}
);

Meteor remote collection - hooks don’t work

I have to connect to the external database and get access to its collections. It works fine, when I use it, but the problem is when I need collection hooks, e.g. Collection.after.insert(function(userId, doc)). The hook is not being fired. I have following code:
// TestCollection.js
let database = new MongoInternals.RemoteCollectionDriver("mongodb://127.0.0.1:3001/meteor",
{
oplogUrl: 'mongodb://127.0.0.1:3001/local'
});
let TestCollection = new Mongo.Collection("testCollection", { _driver: database });
module.exports.TestCollection = TestCollection;
console.log(TestCollection.findOne({name: 'testItem'})); // writes out the item correctly
// FileUsingCollection.js
import { TestCollection } from '../collections/TestCollection.js';
console.log(TestCollection.findOne({name: 'testItem'})); // writes out the item correctly second time
TestCollection.after.update(function (userId, doc) {
console.log('after update');
}); // this is NOT being fired when I change the content of remote collection (in external app, which database I am connected)
How to make this work?
EDIT:
I have read many hours about it and I think it might be connected with things like:
- oplog
- replicaSet
But I am newbie to Meteor and can’t find out what are those things about. I have set MONGO_OPLOG_URL and I added oplog parameter to database driver as I read here: https://medium.com/#lionkeng/2-ways-to-share-data-between-2-different-meteor-apps-7b27f18b5de9
but nothing changed. And I don’t know how to use this replicaSet, how to add it to the url. Anybody can help?
You can also try something like below code,
var observer = YourCollections.find({}).observeChanges({
added: function (id, fields) {
}
});
You can also have 'addedBefore(id, fields, before)', 'changed(id, fields)', 'movedBefore(id, before)', 'removed(id)'
For more features goto link.

How do I prefetch url's in ionic/angularjs?

I am pretty new to ionic 1 and I am working on an application (with Ionic 1 and angular js) with multiple URLs where each URL brings up a list of categories, followed by a list of items for each category and each item has a document URL. How do I preload all these URLs on launch in the background but not display them?Is there any way this can be achieved? a good code sample or tutorial will help greatly.
Also, please let me know if this will be the best approach, as in pre-loading and pre-caching all content upon launch or should it be done category by category or some other way.
Thanks in advance!
You can make multiple Asynchronous service calls in background using $q.
Make a list of URL's in an array and call them at once using $q.all(listOfURL).
Using promises retrieve each response.
By making this asynchronous you can save lot of time.
After getting response you can either store them in $rootScope or in localStorage/sessionStorage.
Update - As the OP is already aware of and using localStorage, thus additional suggestions :-
In that case, you could either call all of your service methods for fetching data at startup or you could use a headless browser such as 'PhantomJS' to visit these URLs at startup and fetch the data.
Thus, your code would look something like :-
var webPage = require('webpage');
var page = webPage.create();
page.open('http://www.google.com/', function(status) {
console.log('Status: ' + status);
// Do other things here...
});
For more information, regarding PhantomJS, please refer to the following links :-
http://phantomjs.org/
http://phantomjs.org/api/webpage/method/open.html
Earlier Suggestions
Make an HTTP request in your service to fetch the data and store it to localStorage, as is shown below :-
$http.get('url', function(response) {
var obj = response.data;
window.localStorage.setItem('key', JSON.stringify(obj)); // Store data to localStorage for later use
});
For fetching data :-
var cachedData = JSON.parse(window.localStorage.getItem('key')); // Load cached data stored earlier
Please refer to the following link for detailed information regarding 'localStorage' :-
https://www.w3schools.com/html/html5_webstorage.asp
Hope this helps!
Best way to share data between different views in angular is to use a service as it is a singleton and can be used in other controllers.
In your main controller you can prefetch your lists of categories asynchronously through a service which can be shared for next views.Below is a small demo which you refer
angular.module("test").service("testservice",function('$http',$q){
var lists = undefined;
// fetch all lists in deferred technique
this.getLists = function() {
// if lists object is not defined then start the new process for fetch it
if (!lists) {
// create deferred object using $q
var deferred = $q.defer();
// get lists form backend
$http.get(URL)
.then(function(result) {
// save fetched posts to the local variable
lists = result.data;
// resolve the deferred
deferred.resolve(lists);
}, function(error) {
//handle error
deferred.reject(error);
});
// set the posts object to be a promise until result comeback
lists = deferred.promise;
}
// in any way wrap the lists object with $q.when which means:
// local posts object could be:
// a promise
// a real lists data
// both cases will be handled as promise because $q.when on real data will resolve it immediately
return $q.when(lists);
};
this.getLists2=function(){
//do it similarly as above
};
}).controller("mainController",function(testservice,$scope){
$scope.lists1=testervice.getLists()
.then(function(lists) {
//do something
});
};
$scope.lists2=testervice.getLists2()
.then(function(lists) {
//do something
});
};
$scope.lists1();
$scope.lists2();
}).controller("demoController1",function(testservice,$scope){
$scope.lists1=testervice.getLists()
.then(function(lists) {
//do something
});
};
$scope.lists2=testervice.getLists2()
.then(function(lists) {
//do something
});
};
$scope.lists1();
$scope.lists2();
});
I am assuming you don't want to load data in next screens, deliver user flawless experience.
Yes you can start loading URLs on you very first page as you want them to get the data you want to use in future screens.
In terms of storage
In AngularJs if you want something to persist throughout the application scope you should use $rootscope[beware keeping lot of data
may leads to memory issues, you need to clear it regularly].
Or another option is to store it in Localstorage. And fetch as per your need.
If you want you can share those arrays between different controllers of screens.
While loading[response getting from server] you can do two things
1. get single JSON response having all the data
2.have multiple urls, and load them serially.
As per your requirement of loading 5th (page)screen data in advance it's not good practice, and even stop user from seeing updates but as it's your requirement. We've couple of approaches:
Add all the category and their respective details as per your pastebin like cardiac then it's details.. kidney then details..
You can do this with managing hierarchies [categories] like parent main group and it's child sub group in JSONArray and details in JSONObject. (This change would be on sender side -server)
You need to load only one url to get all data.
So you don't need to load with different urls like now your doing. But beware this would be a big Json. So when you store it separate the categories and required data [screen-wise requirements] and store in local storage so easy for access.
Another approach would be you have to provide your [category] subgroup names to load so the loading would be like firing same URL with different category names to get data and store it in local storage.
This may lead to fire around 10-15[depends on your categories] urls may affect the UI thread response.
This won't need any changes on your server side response.
**
Programmatically approach to load urls sequentially:
**
URL Loading: This method will get detail of particular category [id or anything
works for you]. This will fire a http request and return a result.
getCategoryDetails(category){
url = url+category;
return $http({
method: 'GET',
url: url,
headers: --
}).then(function onSuccess(response) { //<--- `.then` transforms the promise here
//You can ether store in local storage
return response
}, function onError(response) {
throw customExceptionHadnler.getErrorMsg(response.status, response.data);
});
}
Parallel : This method will do it in parallel, we just load categories[ids] as we have all of them and then use $q.all to wait for all the urls loading to finish.
function loadUrlsParallel(urls) {
var loadUrls = []
for(var i = 0; i < urls.length; i++) {
loadUrls.push(getCategoryDetails(urls[i]))
}
return $q.all(loadUrls)
}
First API: This method to load first url and then Loading urls in
parallel call above method
getListOfCategories(){
url = url;
return $http({
method: 'GET',
url: url,
headers: --
}).then(function onSuccess(response) { //<--- `.then` transforms the promise here
//You can ether store in local storage or directly send response
return response
}, function onError(response) {
throw customExceptionHadnler.getErrorMsg(response.status, response.data);
});
}
urls : you have to prepare list of urls with appending category to
load after loading first url[expecting this returns you all the
categories you will require in your app beforehand] and pass to
loadUrlsParallel method.
You can write loadUrl methods as per your convenience, here whatever
is given is foe example purpose so may not run as it is.
You can load API responses every where from local storage where you've stored after API calls, So this will not ask you to execute API calls on every laoding of pages[screen]
Hope this helps you and solves your prob.

Best practice for multiple AJAX API calls that require a response from the previous call?

I'm working on an internal page that allows a user to upload a CSV with resources and dates, and have the page add all the scheduling information for these resources to our management software. There's a pretty decent API for doing this, and I have a working model, but it seems...cludgy.
For each resource I have to start a new session, then create a new reservation, then add resources, then confirm that the reservation isn't blocked, then submit the reservation. Most of the calls return a variable I need for the next step in the process, so each relies on the previous ajax call.
Currently I'm doing this via nested ajax calls similar to this:
$.ajax('startnewsession').then($.ajax('createreservation').then('etcetc'))
While this works, I feel like there has to be an easier, or more "proper" way to do it, both for cleaner code and for adaptability.
What you're doing is correct, assuming you can't change the API you are communicating with.
There's really no way of getting around having to do some sort of nested ajax calls if you need the response data of the previous one for the next one. Promises (.then) however make it a bit more pretty than having to do callbacks.
The proper solution (if possible) would of course be to implement your API in such a way that it would require less roundtrips from the client to the server. Considering there's no user input in between each of these steps in the negotiation process for creating a reservation, your API should be able to complete the entire flow for creating a reservation, without having to contact the client until it needs more input from the user.
Just remember to do some error handling between each of the ajax calls in case they should fail - you don't want to start creating the following up API calls with corrupt data from a previously failed request.
var baseApiUrl = 'https://jsonplaceholder.typicode.com';
$.ajax(baseApiUrl + '/posts/1')
.then(function(post) {
$.ajax(baseApiUrl + '/users/' + post.userId)
.then(function(user) {
console.log('got name: ' + user.name);
}, function(error) {
console.log('error when calling /users/', error)
});
}, function(error) {
console.log('error when calling /posts/', error)
});
Short answer: as usual I'm trying to do some chains like this:
ajaxCall1.then(
response => ajaxCall2(response)
).then(
response => ajaxCall3(response)
)
I'm trying to avoid using of when. As usual I (and bet you too) have 1 ajax call (for form submit), sometimes 2 chaining ajax calls, for an example, if I need to get data for table, first query for total rows count, and if count greater than 0, another call for data. In this case I'm using:
function getGridData() {
var count;
callForRowsCount().then(
(response) => {
count = response;
if(count > 0) {
return callForData();
} else {
return [];
}
}
).then(response => {
pub.fireEvent({
type: 'grid-data',
count: count,
data: response
})
})
}
publisher trigger event, and I have all my components updated.
In some realy rare cases, I need to use when. But this is always bad design. It happen in case, when I need to load pack of additional data before of main request, or when backend not support bulk update, and I need to send pack of ajax calls to update many of database entities. Something like this:
var whenArray = [];
if(require1) {
whenArray.push(ajaxCall1);
}
if(require2) {
whenArray.push(ajaxCall2);
}
if(require3) {
whenArray.push(ajaxCall3);
}
$.when.apply($, whenArray).then(() => loadMyData(arguments));

ExtJS 4 - Update/Refresh single record

I have a problem that's bugging me.
I have a grid and when i dblclick on a item I want to open a window to edit that item. Pretty standard stuff. The problem is, i want to be sure the record is up to date, because other people using the program may have changed it or even deleted it.
I could reload the store, but i only want one specific record to be checked... So i figured i would just go get the data, build another record and replace the existing one in the store but i really want to know the best way to do this
Bear in mind RESTful proxy is not an option for me, even though i don't know if the update operation works in this case ( server -> client).
EDIT:
this may help somebody:
all i did was copy the data and raw objects from the new record to the old one and then "commit" the changes. worked for me.
Thank you.
ExtJS 4.1
I had a similar problem and as an experiment tried
sStore.load({
id: mskey,
addRecords: true
});
where mskey is a uuid of a currently loaded record.
I did not remove the existing record first (as an experiment) and it updated the existing record that had the same id with the new data from the server (via the model --> REST proxy). Perfect!
I know you said you are not using a REST proxy, but this might help others who found this post searching for search terms like your topic name (which is how I got here!)
So, it looks like 'addRecords' means add or update.
FYI,
Murray
The best way to do something like this would be to reload the record in the event which opens the window. So where you would for example load the record from the grid store into a form within the window, you can use your model to load from the id.
Item.load(id, { success: function(r) { form.loadRecord(r); } });
Once saved, you should probably also call refresh on the grid view, which will redraw the changes from the save event. You can also use refreshNode (see grid view documentation) on the exact record in the store if you're concerned about performance.
Of course you do not have to use the restful proxy with this, you can use any proxy as long as it will load the single record.
With ExtJS 4.1, here is an override :
In CoffeeScript :
# Adds "reload" to models
Ext.define "Ext.ux.data.Model",
override: "Ext.data.Model",
# callBack is called with success:boolean
reload: (callBack) ->
Ext.getClass(#).load #getId(),
success : (r, o) =>
for k, v of r.data
#data[k] = v
#commit()
callBack(true) if Ext.isFunction(callBack)
failure: =>
callBack(false) if Ext.isFunction(callBack)
In JS (did not test) :
Ext.define("Ext.ux.data.Model", {
override: "Ext.data.Model",
reload: function(callBack) {
var me = this;
return Ext.getClass(this).load(this.getId(), {
success: function(r, o) {
var k;
for (k in r.data) {
me.data[k] = r.data[k];
}
me.commit();
if (Ext.isFunction(callBack)) {
callBack(true);
}
},
failure: function() {
if (Ext.isFunction(callBack)) {
callBack(false);
}
}
});
}
});
I created an override on the Ext.data.Model to add an additional method that can be used to update the data of an existing record (model instance).
Ext.define('Ext.overrides.data.Model', {
override: 'Ext.data.Model',
/**
* Refresh the data of a record from the server
*/
reloadData: function(cb) {
var me = this;
var id = me.getId();
Ext.ModelManager.getModel(me.modelName).load(id, {
callback: function(record, operation, success) {
if (!success) {
Ext.Error.raise('Problem reloading data from server in record');
}
if (!record) {
Ext.Error.raise('No record from server to reload data from');
}
//change the data of the record without triggering anything
Ext.apply(me.data, record.getData());
//call a final callback if it was supplied
if (cb) {
cb.apply(me, arguments);
}
}
});
return me;
}
});
This is how you can use it. It's actually pretty simple:
myRecord.reloadData(function(record, operation, success) {
//Done updating the data in myRecord
});
Internally it uses the load method on the associated model to create a new record. That new record is based on the same id as the original record that the reloadData method was called on. In the callback the data of the new record is applied to the data of the original record. No events triggered, which is probably hat you want.
This is Ext 4.2.1. There's probably dozens of scenario's that this solution breaks but we can always refine can't we.
Update: This solution basically implements the same as the one by #Drasill. Oh well... This one was tested though.

Categories

Resources