I'm developing a site (D6) that runs geocode lookups every time a node is inserted or updated, the node has an address textfield and hidden fields for a lat/lng pair, and during hook_nodeapi I want to call this geocoding function.
The issue is that the geocoder needs to save this new latlng pair to the node, which in turn calls hook_nodeapi, and thus my recursion issue has been spawned.
Whats the best method for avoiding this headache?
If you are completly sure, that you cannot change geocoder behavior, you can use simple workaround:
static $geocoded_nodes = array();
if (!$geocoded_nodes[$node->nid]) {
$geocoded_nodes[$node->nid] = TRUE;
call_geocoder_stuff().
}
As alternative, You can also can try to add non used field to node passed to geocoder logic.
if (!isset($node->geocoding_done)) {
$node->geocoding_done = TRUE;
call_geocoder_stuff($node).
}
I'm not sure if this field won't be discarded on node_save logic, but this should work.
Related
I have created a simple Pre Trigger in my CosmosDB collection.
function testTrigger() {
var context = getContext();
var request = context.getRequest();
var documentToCreate = request.getBody();
documentToCreate["test"] = "Added by trigger";
request.setBody(documentToCreate);
}
Though it seems, this trigger isn't fired at all.
What's also irritating, the getContext() call is marked with a green squiggly line in the script explorer.
The problem that the trigger doesn't seem to be... well... triggered, is that you aren't specifying it on the triggering operation. Triggers are not automatic. They must be specified for each database operation where you want them executed.
Personally, I think that was a unfortunate design choice and I've decided to not use triggers at all in my own code. Rather, I embed all the business rule constraints in stored procedures. I find this to be a bit cleaner and removes the worry that I'll forget to specify a trigger or (more likely) someone else writing code to the database won't even know that they should. I realize that someone can bypass my stored procedure and violate the business rules by going directly to the documents, but I don't know of any way in DocumentDB to protect against that. If there was a way to make triggers be automatic, that would have protected against that.
When using the REST API, you specify triggers in a header with x-ms-documentdb-pre-trigger-include or x-ms-documentdb-post-trigger-include. In the node.js SDK, you use the RequestOptions preTriggerInclude or preTriggerInclude property. For .NET, you specify it like this:
Document createdItem = await client.CreateDocumentAsync(collection.SelfLink, new Document { Id = "documentdb" },
new RequestOptions
{
PreTriggerInclude = new List<string> { "CapitalizeName" },
});
See comments for discussion on the green squiggly.
I understand this may be an elementary question, but I'm new to Asp.net webforms, so please bear with me.
I have a lengthy form on a page that I would like to autosave when users type in a field, or make a selection. The problem is, all I've been able to find online is autosaves that work on a timer. I'd prefer that it saves as the user makes their edits. Also I would like just the individual form element being edited to be sent to the server to avoid sending the entire page back each time.
I've read that I should use a webservice to accomplish this, but since I want to autosave individual items and not the whole form on a timer, how would I set up a webservice to accomplish this? I'm new to webservices I'd like to know what to read up on. Any links are appreciated.
Also, how is the autosave functionality effected when using asp.net validation controls? I've looked around but can't tell if the entire page needs to be valid to make a trip to the server, or if just a single valid item can be sent itself.
Thanks for any help!
If you set AutoPostBack=True on the field, and you add an OnChange event for it (this will vary depending on the type of field the user is interacting with), you can execute a save. Don't call Page.Validate in the methods where you're doing these updates. Call it when you hit the Submit button.
This could cause a LOT of round trips to the server, and it's a lot of code to write and debug.
The Timer approach is one call to one method on a repetitive basis. If you can I'd recommend going with a timer, but sometimes that's not an option.
Generally speaking this is what you'll want to setup on the client-side. Ideally, you will end up with lots of tiny requests which do not require much power on the back-end. This however depends on lots of variables including the database engine you're using.
$(document).ready(function () {
$("input").blur(OnFieldChanged);
});
function OnFieldChanged()
{
var $this = $(this);
var isValid = ValidateField($this);
if (isValid)
{
SaveField($this);
}
}
function SaveField($field)
{
if ($this.val() === $this.prop("oldVal")) return;
var data = {
id: $("idfield").val()
};
data[$field.attr("id")] = $field.val();
$.post({..}).done(function() {
NotifySaved($this);
$this.prop("oldVal", $this.val());
});
}
function ValidateField($field)
{
// Validate the field with your method of choice, manually call Microsoft's client-side validate function or switch to jquery validate.
return true;
}
I am wanting to display waypoints on a Google Maps API driven map which have not already been visited by a specific person.
I have two collections in MongoDB currently.
waypoint: consists of location and a guid (among other things)
visit: consists of a player's guid and a waypoint guid
What I want is:
The waypoints sent to the client are only the ones which can appear on the current map's bounds.
If the map is moved (the bounds change), new waypoints will appear as needed. Ideally the old ones would be removed from the client as they fall out of view as well.
If a new waypoint is added, it would be added to the map for the person.
If that player then visits that waypoint, adding the associated record to the visits database would cause the waypoint to disappear from the map.
If the waypoint is deleted or updated, it is removed or updated on the map as well.
I'm still very new to Meteor, and while I think I understand a single subscription (or even multiple subscriptions for the same collection) well, I am having trouble coming up with a reactive solution that doesn't involve pouring a lot of data into the browser.
I'm having problems figuring out how to combine this into something simple. I fear there is no way, but links to options would help.
When you describe sounds doable. Have a look at understanding Meteor publish/subscribe first then revisit the problem.
The way I'd structure the publication would be like this:
// server - takes care of requirements 1, 3 and 5
Meteor.publish('waypoints-within-bounds', function publishFunction(bounds) {
return Waypoints.find({
location: {
$geoWithin: {
$box: [ bounds.bottomLeft, bounds.upperRight ]
}
},
guid: {
$nin: // array of visited waypoint guids; Mongo doesn't have joins
}
});
});
// client - this takes care of requirement #2
Tracker.autorun(function () {
Meteor.subscribe('waypoints-within-bounds', Session.get('mapBounds'));
});
function updateMapBounds() {
var bounds = map.mapObject.getBounds();
// massage developers.google.com/maps/documentation/javascript/reference#LatLngBounds
// to match MongoDB's $box parameter order: [...]
Session.set('mapBounds', bounds);
}
google.maps.event.addListener(map.mapObject, 'center_changed', updateMapBounds);
google.maps.event.addListener(map.mapObject, 'zoom_changed', updateMapBounds);
The above are raw calls to the Google Maps API, but you'll probably want to use dburles:google-maps.
Now we need to take care of the last requirement: "If that player then visits that waypoint, adding the associated record to the visits database would cause the waypoint to disappear from the map." That's best done with a Meteor.method which you'll call from the client when a waypoint is visited.
Going forward, you might want to have template-level subscriptions instead, and keep an eye on this feature making it into Meteor core.
I want to wait for all data to be downloaded from the subscription and then create map markers for them all at once at the beginning. To do this, I have a session variable set to false. Then when onReady calls, I initialize all the markers. Then I set the session variable true indicating that the first delivery is in and initialized. In my observe callback, I check the session variable and so long as its false, I dont add any markers. Then, if its true, I will add markers -- assuming non of these markers are already initialized. Sometimes, however, I get a double-count and create twice as many markers.
I guess a good first question to ask is what the relationship is between onReady and observe added? Its not terribly clear in the docs. Is this even the correct way of doing things -- creating a session variable to suppress the observe added function until onReady is done? I dont think so. Also note that the double count doesnt happen every time so its a timing thing... kind of annoying.
Thanks
Yes this is the behavior with observe(). When you run observe initially it will have an initial query that will match everything and run into added.
It is also present when onReady hasn't yet fired but the collections are empty at that point so the initial ones aren't visible. This is mentioned in the docs
Before observe returns, added (or addedAt) will be called zero or more times to deliver the initial results of the query.
I'm not sure entirely how to avoid the initial items. I have done something like this in the past:
var QueryHandle = Collection.find().observe({
added: function() {
if(!QueryHandle) return false;
});
I know this works on the server but I'm not certain if it does on the client.
Another solution would be to run the handle before onReady is called and only stop returning if the subscription is complete: i.e
Meteor.subscribe("collection", function() {
subscribed = true;
});
var QueryHandle = Collection.find().observe({
added: function() {
if(!subscribed) return false;
}
);
Be careful not to run this in a Deps.autorun because then it would be run again if the .find() query params are reactive.
This might happen sometimes depending on how fast the server response. If you use Session it becomes a reactive hash so if it happens fast enough that subscribed returns true. Try using an ordinary variable instead.
If its not helpful there might be an alternative way to avoid the initial ones and a deeper level but it might take a dig into the livedata package.
Here's my scenario. When child is added via a browser event post page load, I want to indicate it in the title. But on page load, child added is called as well.
How can I differentiate the initial child added vs one where a new entry has been actually added.
Thanks, Tim
Firebase very intentionally does not distinguish "initial" data from "new" data. This allows for much simpler development in most cases, because you only have to write one set of logic for your data, rather than handling both the initial data case and the new data case.
I can see how you would want the distinction in this case. I'm not sure exactly what you're doing, but if you're building a chat application, you might want to flash the title based on the timestamp of the most recent message rather than whether or not it's a "new" message. This would allow the title to flash on page load if a message was sent slightly before the page was loaded, which may be desirable. In some other cases, you may actually want to flash the title for unread data, and you may want to consider marking children as "read" and flashing the title only for children that show up without the "read" bit. This would allow things to work seamlessly across page refreshes.
If you absolutely need to know when "new" data shows up, you could try using "once" with a "value" event type to get the data, and then use "on" with a startAt query and a "child_added" event type to display new data after that. It would look something like this:
var data = new Firebase(...);
data.once("value", function(d) {
//TODO: display initial state...
data.startAt(null, <last id in snapshot>).on("child_added", function(newMessSnapshot) {
//TODO: render new child and flash title bar.
}
}
Or if you want to do it the really simple way, you could just set a timer so that the title won't flash for any messages received within the first N seconds of page load.
Hope that helps!
You can set up a call that only receives new events rather than ones already existing using the approach from this SO question.
So basically, call .on('child_added'...) with endAt and limit. You still get one entry (the last one), which you can just ignore:
// connect to firebase
var fb = new Firebase(...);
// retrieve the last record from `ref` (endAt() tells it to start at the end)
var first = true;
fb.child('table_name').endAt().limit(1).on('child_added', function(snapshot) {
if( first ) {
// ignore the first snapshot, which is an existing record
first = false;
return;
}
// all records after the last continue to invoke this function
console.log(snapshot.name(), snapshot.val());
});
I thought I would update Kato's answer as Datasnapshot.name() and limit have now both been depreciated.
I decided to make it a bit more simple as well ;)
// connect to firebase
var fb = new Firebase("https://your-firebase-ref/");
var firstTime = false;
fb.limitToLast(1).on('child_added', function(snapshot) {
if (firstTime) {
console.log(snapshot.key(), snapshot.val());
};
firstTime = true;
});
I hope this helps