Destroy Backbone model using async=false - backbone.js

I try to pass {async: false} to the destroy function of my model but it doesn't work:
m.destroy({
async: false,
success: function(){
console.log('destroyed');
}
});
console.log('already destroyed');
I see the second log before the first one. Am I missing something or async doesn't work for destroy?

Please look for my project which was created for testing Backbone-Debugger (Chrome plugin)
https://github.com/piecioshka/test-backbone-debugger
Please let me know, if it's helpful!

Related

How can I save my data using localStorage in AngularJS?

I am working on a To-Do list app and would like to save data on the local storage of the device, but I can't figure out what it is I need to do.
In my app.js file I have the following code which allows me to add new tasks and to edit them:
.controller('DashCtrl', function($scope, $ionicPopup, $ionicListDelegate) {
$scope.tasks =
[
{title:"Example 1", completed: true},
{title:"Example 2", completed: false},
];
$scope.newTask = function(){
$ionicPopup.prompt({
title:"New Task",
template: "Enter task:",
inputPlaceholder:"Please add your task",
okText:'Create task'
}).then(function(res){
if (res) $scope.tasks.push({title: res, completed: false});
})
};
$scope.edit = function(task){
$scope.data = { response: task.title};
$ionicPopup.prompt({
title: "Edit Task",
scope: $scope
}).then(function(res){
if(res !== undefined) task.title = $scope.data.response;
$ionicListDelegate.closeOptionButtons()
})
};
The data is stored in the scope so I tried the following:
localStorage.setItem(scope));
And my idea is to call this function every time a new task is added, so that the storage is always up to date. But this does not seem to be working, what am I doing wrong?
This is the way to go:
https://github.com/gsklee/ngStorage
"An AngularJS module that makes Web Storage working in the Angular Way. Contains two services: $localStorage and $sessionStorage."
localStoragestores strings. If your data is already a string, a simple
localStorage.setItem($scope.data) should work. If it's a valid JSON, you stringify it and store as before.
localStorage.setItem(JSON.stringify($scope.data))
#Ladmerc would this work?
$scope.newTask = function(){
$ionicPopup.prompt({
title:"New Task",
template: "Enter task:",
inputPlaceholder:"Please add your task",
okText:'Create task'
}).then(function(res){
if (res) $scope.tasks.push({title: res, completed: false});
localStorage.setItem(JSON.stringify($scope.data));
localStorage.setItem($scope.data);
})
};
I think there are multiple issues with your approach, first being that you are trying to save the whole $scope object, you can place a console.log() to see how much data it contains, spoiler alert, a lot. The $scope object can be huge and there is no need to save it, what you want is to save the tasks. As mentioned by others, you also need to stringify your data, because localStorage only accepts strings. Luckily you don't have to solve these issues yourself, I would highly recommend you take a look at localForage, it is a library that:
localForage is a fast and simple storage library for JavaScript.
localForage improves the offline experience of your web app by using
asynchronous storage (IndexedDB or WebSQL) with a simple,
localStorage-like API.
You can find more information about localForage in the documentation and there is also an Angular wrapper available.
In your case, this would be an example of how to use this library:
$localForage.setItem('tasks', $scope.data).then(function() {
console.log("The tasks have been saved!");
});

Adding new data to a state in react.js

I working on a project where I am using react.js with laravel where I am using react for adding new comment in a post for that I am trying to to react's state but I want to add new data retrieved from server in my state without deleting or erasing old data present from that state. How can I achieve that method, is there any dependency for that, or any example or tutorial for that? Even If I am going with wrong approach then also please tell me what approach will be perfect.
The sample code for my problem -
I've an ajax function to get data initially.
getData: function() {
$.ajax({
url: '/get-data',
dataType: 'json',
cache: false,
success: function(data) {
this.setState({
data: data
});
}.bind(this)
});
}
and now after triggering new event I want to update my state without loosing my old data.
Thank you.
You should use the react immutability helpers
This allows you to update nested parts of the state without having to reset the whole thing. If you are just manipulating the root level properties of the state (e.g. this.state.blah or this.state.foo) then this.setState({ foo: 'a value'}); will leave the other root elements as they were.
If you do then want to completely reset the state you can use replaceState({});
setState
replaceState
If data in your code is a valid JSON object, you can use something like:
object-assign
lodash.merge
to merge your data before setting it to state.data. An example using lodash.merge:
import merge from 'lodash.merge'
// some of your code
// inside your getData function in your components
$.ajax({
success: function (data) {
this.setState({
data: merge({}, this.state.data, data)
});
}.bind(this)
});
Whilst it may be not a good practice to be doing this sort of wholesome replacement, it should address your issue. What might be a better approach is not really a scope of this answer :D

Testing backbone router with jasmine and sinon. Cannot call the pushState.

I was following this question to test the router. My router is really simple:
App.Router = Backbone.Router.extend({
routes:{
"": "index",
"help": "help"
},
help: function() {/* not really needed */ },
index: function(){
// does something
}
});
And this is an apptempted translation of what should be the test using jasmine with sinon:
it('triggers the "index" route', function() {
var router = new App.Router();
Backbone.history.start();
//Not calling navigate it's a problem
router.navigate('help', {
trigger : true, replace: true
});
var index = sinon.spy(router, 'index');
var spyHasPS = sinon.spy(function(
data, title, url) {
expect(url).toEqual('/');
router.index();
});
var spyNoPS = sinon.spy(function(loc, frag) {
expect(frag).toEqual('');
router.index();
});
if (Backbone.history._hasPushState) {
pushStateSpy = sinon.stub(window.history, 'pushState', spyHasPS );
// window.history.pushState();
} else if (Backbone.history._wantsHashChange) {
pushStateSpy = sinon.stub(Backbone.history, '_updateHash', spyNoPS);
//Backbone.history._updateHash(window.location, '');
}
router.navigate('', {
trigger : true, replace: true
});
expect(pushStateSpy.called).toBe(true);
expect(index.called).toBe(true);
});
This test works but I could achieve it because I navigated first on "help". "help" was just something I created to pass the test but the original question didn't do it and was passing. Did I do something wrong? I also run his test but the error I'm getting is:
Expected spy _updateHash to have been called. Error: Expected spy
_updateHash to have been called.
at null.<anonymous> (/src/test/js/spec/wfcRouter.spec.js:65:32) Expected spy index to have been called.
I believe the "problem" is in the navigate function. At a certain point in the navigate: function(fragment, options) we have this control:
fragment = this.getFragment(fragment || '');
if (this.fragment === fragment) return;
So...does it make sense to test the pushState when you just have one route (remember I added "help" just to make this test pass so I don't need it)? If it does make sense, how can I achieve this test?
It seems like what you are testing is Backbone code, but there's no need for you to test that: presumably the Backbone code has been tested plenty by Jeremy Ashkenas (and if you look at the Backbone project on GitHub you will see that he does in fact have a comprehensive test suite). So, rather than re-testing code you didn't write that's already been tested, what you really should be testing is the code you wrote.
If you agree with that principle, then you can simplify your test a great deal, down to just:
it('triggers the "index" route', function() {
var router = new App.Router();
router.index();
expect(thingThatShouldHaveHappenedInIndexRouteDidHappen).toBe(true);
});

CakePHP and AJAX to update Database without page refresh

I'm working with CakePHP 1.3.7 and I'm trying to do the following:
On a given page, the user can click a link (or image, or button, doesn't matter) that passes a parameter which is saved into a database. BUT, all this, without refreshing the page.
I've been doing some research and I believe I need to use AJAX as well to acomplish this. However, I can't find the a good example/explanation on how to do it.
I think that the idea is to create the link using AJAX, which calls the controller/action that would receive the variable as a parameter and performs the operation to save it in its corresponding field/table of the DB.
Does anyone have a small example of what I want to do? Or maybe point me to some tutorial that explains it... Thanks so much in advance!
EDIT
Well, thank you guys for your replies. THey're not working directly, but I think I'm getting closer to what I want. Here's what i'm doing now:
I have this code in my view:
<div id="prev"><a>click me</a></div>
<div id="message_board"> </div>
I call this JS file:
$(document).ready(function () {
$("#prev").click(function(event) {
$.ajax({data:{name:"John",id:"100"}, dataType:"html", success:function (data, textStatus) {$("#message_board").html(data);}, type:"post", url:"\/galleries\/add"});
return false;
});
});
And my add action in my galleries controller looks like:
function add() {
$this->autoRender = false;
if($this->RequestHandler->isAjax()) {
echo "<h2>Hello</h2>";
print_r($this->data);
$this->layout = 'ajax';
if(!empty($this->data)) {
$fields = array('phone' => 8, 'modified' => false);
$this->User->id = 6;
$this->User->save($fields, false, array('phone'));
}
}
}
When clicking on the '#prev' element, I get a response from the add action, I know because the text 'Hello' is printed inside #message_board. And it does this without refreshing the page, which is why I need. My problem is that I can't make the $.ajax() function to send any data, when it gets to the controller the $this->data is empty, so it never goes inside the if that saves the info to the database (right now it's saving just an easy thing, but I will want it to save the data that comes from the view).
Can anyone see what am I doing wrong? How can I send the data to the controller?
CakePHP does not matter, most of the code you would need for this would be at clientside. Implementing AJAX by yourself is a pain in the $, so you really want to use a library; currently the most popular is probably jQuery. There's a bunch of examples on their AJAX page: http://api.jquery.com/jQuery.ajax/
So, assuming you have something like this in the document:
<form id="s">
<input id="q"/>
<input type="submit" href="Search!"/>
</form>
<div id="r"/>
you can put this in the JavaScript:
$('#s').submit(function(evt) {
evt.preventDefault();
$.ajax({
url: 'foo.php',
data: {
query: $('#q').val()
},
success: function(data) {
$('#r').html(data);
}
});
return false;
});
Then your foo.php only needs to return the fragment HTML that would go into the div#r.
EDIT: I forgot to stop the submit :( Thanks to #Leo for the correction.
EDIT: I can see what your confusion is about. You will not get a data. I haven't worked with CakePHP, but I assume $this->data is what you'd get from $_REQUEST['data']? You don't get that on the server. data is a hash of what is getting submitted; you will directly get the $_REQUEST['name'] and $_REQUEST['id'] (which, I assume, translate into CakePHP as $this->name and $this->id).
You need to add
$('#s').submit(function(evt) {
evt.preventDefault();
To prevent a page refresh, as in Amadans answer just refer to your controller/ action in the url variable
$('#s').submit(function(evt) {
$.ajax({
url: '/patients/search/',
data: {
query: $('#q').val()
},
success: function(data) {
$('#r').html(data);
}
In the patients/add controller action make sure you return a valid result ( in json is good )

Extjs Load panel content from ajax

I have an Ext.Panel with a listener set to 'afterrender'. The callback function is a small ajax code which checks an url, grabs it's contents and add it to the panel. Problem is, the content does not get insterted. If I use the same insert code right above the ajax call, it works. Here's my callback function:
Not working:
function afterrenderCallback () {
// This does not work
var logPanel = Ext.getCmp('aP_ServerLogs');
Ext.Ajax.request({
url: AP_ROOT_URL + '/index.php?r=server/logs',
success: function (r) {
logPanel.add({
html: 'dummy html i don\'t care about the response'
});
}
});
}
Working:
function afterrenderCallback () {
// This does work
var logPanel = Ext.getCmp('aP_ServerLogs');
logPanel.add({
html: 'dummy html i don\'t care about the response'
});
}
You might need to call doLayout() on the panel. However check out Ext.Updater:
http://dev.sencha.com/deploy/dev/docs/?class=Ext.Updater
Panels have this automatically such as:
var panel = new Ext.Panel({
});
panel.body.load(...);
panel.body.update(...);
I'd suspect the callback isn't getting called. You could add a failure case with a simple alert call to check it's not going down that path.
However probably better, similar to what #Lloyd said, you should look at the autoLoad config property.
The autoLoad config is what you want, as mentioned. I wanted to add that doing a logPanel.add({...}) just to insert markup is not appropriate, even though it "works". There is no reason to nest a panel within a panel for this. If you are loading HTML content like this you'd preferably do logPanel.body.update('content');.
As #bmoeskau says, the autoLoad config is what we need. It took me quite a while to find the correct syntax though. So here is an example on how to define such a panel with ajax content:
Ext.define('MyApp.view.aP_ServerLogs', {
extend : 'Ext.panel.Panel',
id: 'aP_ServerLogs',
loader: {
url: AP_ROOT_URL + '/index.php?r=server/logs',
autoLoad: true
}
});

Resources