Persist state params when calling $state.go - angular-ui-router

There's a route param that represents the current site language, defined in the abstract app state.
angular.module("app", ["ui.router"]).config(["$stateProvider",
function($stateProvider) {
$stateProvider
.state('main', {
url: '/:lng',
abstract: true,
template: '<div ui-view></div>'
})
.state('main.index', {
url: '/',
template: '<span>Index</span>'
})
.state('main.gallery', {
url: '/gallery',
template: '<span>Gallery</span>',
})
}
]);
For now, everytime calling $state.go, I have to add the lng property to the route param list, like
$state.go('main.index', { lng: 'en' });
even though the current value of lng is en
Is there anyway to make the lng remain the same like the previous state unless we explicitly change it by passing it to the route param list?

You can add a default value to the lng param in your state definition:
.state('main', {
url: '/:lng',
abstract: true,
template: '<div ui-view></div>'
params: {
lng: 'en'
}
})
More detail can be found here

Related

How to validate model using collection.create()

I'm trying to make a form validated before submit. For this, I defined a create method within the View which is responsible to call collection.create() method to create the model.
Here is a sample code:
app.ContactCreateView = Backbone.View.extend({
template: _.template($('#tpl-create-contact').html()),
initialize: function () {
this.router = new app.ContactsRouter();
this.contacts = new app.ContactsCollection();
},
events: {
'click #btn-create' : 'create',
'click #btn-cancel' : 'cancel',
},
render: function() {
this.$el.html(this.template());
return this;
},
getAttributes: function () {
console.log('getAttributes()');
var attr = {
name: $('#input-name').val().trim(),
category: $('#input-category').val().trim(),
phone: $('#input-phone').val().trim(),
email: $('#input-email').val().trim(),
};
console.log('attr : ' + JSON.stringify(attr))
return attr;
},
create: function () {
console.log('create()');
// Create the Model
this.contacts.create(this.getAttributes(), {
wait : true,
success: function () {
console.log('success');
//this.hideErrors();
var router = new app.ContactsRouter();
router.navigate('contacts', true);
},
error: function () {
console.log('error(s)')
//this.showErrors(errors);
}
});
},
The 'success' callback is well called but I don't manage to get the 'error' callback called once the model.validate() method is failing.
Here is the model with the validate method :
app.ContactModel = Backbone.Model.extend({
urlRoot: '/user',
// Default attributes for the Contact
defaults: {
name: null,
phone: null,
email: null,
category: null,
photo: "/images/placeholder.png"
},
validate: function(attrs) {
console.log('validate() : ' + JSON.stringify(attrs));
var errors = [];
if (!attrs.name) {
errors.push({name: 'name', message: 'Please fill name field.'});
}
if (!attrs.category) {
errors.push({name: 'category', message: 'Please fill category field.'});
}
console.log('errors : ' + JSON.stringify(errors));
return errors.length > 0 ? errors : false;
}
});
And the collection:
app.ContactsCollection = Backbone.Collection.extend({
model: app.ContactModel,
url: '/user',
//localStorage: new Backbone.LocalStorage('contacts-backbone'),
getById: function (iId) {
return this.where({id: iId});
},
getByName: function (iName) {
return this.where({name: iName});
}
});
I really don't understand what I'm doing wrong... If somebody can help me :-(
Regards,
when the validation is failed error callback is not called , it trigger an "invalid" event on model, and set the validationError property on the model.
method 1(listening on model):
app.ContactModel = Backbone.Model.extend({
urlRoot: '/user',
//your error catched here
initialize : function(){
this.on("invalid",function(model,error){
alert(error);
});
defaults: {
name: null,
phone: null,
email: null,
category: null,
photo: "/images/placeholder.png"
},
validate: function(attrs) {
console.log('validate() : ' + JSON.stringify(attrs));
var errors = [];
if (!attrs.name) {
errors.push({name: 'name', message: 'Please fill name field.'});
}
if (!attrs.category) {
errors.push({name: 'category', message: 'Please fill category field.'});
}
console.log('errors : ' + JSON.stringify(errors));
return errors.length > 0 ? errors : false;
}
});
method 2 (check whether validationError property is set in your view):
create: function () {
console.log('create()');
// Create the Model
this.contactModel.save(this.getAttributes(), {
wait : true,
success: function () {
console.log('success');
this.contacts.add(this.contactModel);
var router = new app.ContactsRouter();
router.navigate('contacts', true);
},
error: function () {
console.log('error(s)')
}
});
//your error catched here
if (this.contactModel.validationError) {
alert(this.contactModel.validationError)
}
},
So I played around with this for a while in an app I'm currently working on and found it kind of irritating and never really got it to work.
Instead I went the jQuery validation route and found it very helpful for doing validations. I highly recommend checking it out! It has a lot of built in validations you can just use and you can also override the error messages that display (also built in).
Example - I wanted a number only text field (excuse the coffeescript) :).
jQuery.validator.setDefaults(
debug: true,
success: "valid")
if #model.get('number_only')
$('#number_only').validate({
debug: true,
rules: {
"number[entry]": {
required: true,
range: [#model.get('min_number'), #model.get('max_number')],
number: true
}
},
messages: {
"number[entry]": {
required: "This field is required. Please enter a numeric value.",
min: jQuery.validator.format("Please enter a value greater than or equal to {0}."),
max: jQuery.validator.format("Please enter a value less than or equal to {0}."),
number: "Please enter a numeric value"
range: jQuery.validator.format("Please enter a value between {0} and {1}.")
}
}
})
If that doesn't really get what you want (seemed like you maybe are more interested in displaying the errors your server sends back whereas this route would more be validating the content before saving your model) let me know and I can see if I can figure out your problem.

Ext JS: Load single database entry into model

I'm trying to create a model with a single database entry, instead of creating a store for just one row... doesn't make sense. Anyway, I can create the model by using the static load method, but the URL for my model's proxy is dynamic, so that's not an option, as I want to just load on the fly. Also, creating an instance of the model doesn't seem to work because I can't use the load method, due to it being static...
I've started experimenting with an Ajax call to grab the data, and then loading it into an instance of the model, but the association relationships seem to not get created, even though the plain field values do. This is what I'm attempting to do:
Code
// SectionsModel
Ext.define('SectionsModel', {
extend: 'Ext.data.Model',
fields: ['name']
});
// MY_MODEL
Ext.define('MY_MODEL', {
extend: 'Ext.data.Model',
fields: ['name', 'id'],
hasMany: [{
associationKey: 'sections', name: 'getSections', model: 'SectionsModel'
}],
proxy: {
type: 'memory',
reader: {
type: 'json',
root: 'configuration'
}
}
});
var url = 'my/url';
Ext.Ajax.request({
url: url,
method: 'GET',
scope: this,
success: function(res) {
var configObj = Ext.decode(res.responseText);
var configModel = Ext.create('MY_MODEL', configObj);
console.log(configModel);
},
failure: function(res) {
console.error('failed');
}
});
Response
{
"code": 200,
"configuration": {
"name": "TestConfiguration",
"id": 1,
"sections": [{
"name": "section1"
}, {
"name": "section2"
}]
}
}
The above code is dummy code that I wrote for this example... think of it as pseudocode if it doesn't work. Like I said, it does work when I use the static load method, and I can successfully make the Ajax call... the issue is how to create a model with the given data. Would I need to pass in config to the model's constructor, and set the model's proxy's data to the passed in config? Is that proper protocol? I'm just trying to figure out the best approach here. Thanks!
Cross-posted from the Sencha forums.
I have come up with a solution, thanks to one of Mitchell Simoens' blog post. I changed MY_MODEL to look like this:
Ext.define('MY_MODEL', {
extend: 'Ext.data.Model',
fields: ['name', 'id'],
hasMany: [{
associationKey: 'sections', name: 'getSections', model: 'SectionsModel'
}],
constructor: function(data) {
this.callParent([data]);
var proxy = this.getProxy();
if (proxy) {
var reader = proxy.getReader();
if (reader) {
// this function is crucial... otherwise, the associations are not populated
reader.readAssociated(this, data);
}
}
},
proxy: {
type: 'memory',
reader: {
type: 'json'
}
}
});
// in the success of the Ajax call
success: function(res) {
var configObj = Ext.decode(res.responseText);
var configModel = Ext.create('MY_MODEL', configObj.configuration);
console.log(configModel);
}

Multiple Ajax PUTs in Laravel 4 Giving Errors

I am updating my Model through a resource controller via jQuery Ajax Put. No problems at all the first time. This works fine:
$(".addNest").click(function() {
var nid = msg; //once the LI is added, we grab the return value which is the nest ID
var name = $('.nestIn').val();
if(name == '') {
$("textarea").css("border", "1px solid red");
}else {
$.ajax({
type: 'PUT', // we update the default value
url: 'nests/' + nid,
data: {
'name': name
},
success: function(msg) {
alert(msg)
window.location.replace('nests/' + nid ); //redirect to the show view
}
});
}
});
Later in a separate code block, I try to call the PUT again like this:
$(".nestEdit").click(function() {
$(".nestEdit").hide();
var name = $('.nestName').data("name");
var nid = $('.nestName').data("id");
$(".nestName").html("<textarea class='updateNest'>"+ name +"</textarea> <span><a href='#' class='btn btn-mini nestUpdate'><i class='icon-plus'></i> Update</a></span>");
$(".nestUpdate").click(function() {
var updatedName = $('.updateNest').val();
$.ajax({
type: 'PUT', // we update the default value
url: 'nests/' + nid,
data: {
'name': updatedName
},
success: function(msg) {
alert(msg) // showing the error here
location.reload( ); //refresh the show view
}
});
});
The 'updatedName' values and the 'nid' values are passing fine when I 'alert' them. When I view the return for the first PUT it comes back fine. However, when I view the return for the second PUT I get this:
{"error":{"type":"Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException","message":"","file":"\/Applications\/MAMP\/htdocs\/n4\/bootstrap\/compiled.php","line":8643}}
Anyone have some insights here? As you can tell, I am trying to do an inline edit. I have tried to wrap everything into a function but still not helping...
Laravel does not use PUT and DELETE natively since it is not supported in all browsers, you need to send a POST request with '_method' set to either put or delete.
$.ajax({
type: 'POST',
url: 'nests/' + nid,
data: {
'name': updatedName,
'_method': update
},
success: function(msg) {
alert(msg) // showing the error here
location.reload( ); //refresh the show view
}
EDIT: Ajax request do support PUT AND DELETE.
In your JavaScript code, for the inline editing, you are not making proper use of $.
If you click on .nestEdit, it's inner function should not be calling it by name, provided you have multiple objects of the same class on that page. This is why you get the error. Instead of sending the nest ID, it's sending an array object, which your Laravel Router will not pick up, because it is more than likely not defined.
Simply put, you should not be doing this:
$(".nestEdit").click(function() {
$(".nestEdit").hide();
...
You should be making a call to this:
$(".nestEdit").click(function() {
$(this).hide();
...
So, for every .nestEdit within the inner function, you need to call for this instead.

Knockout.Validation Unusable, Any Alternatives? Or Workarounds?

I'm searching for a knockout validation plugin and I stumbled upon knockout.validation which looks very promising, however, it has a fatal flaw..
Once you have created a ko.validatedObservable({ name: foo }) you are not able to assign a new object to that observable.
For Example: In my view model I instantiate a validated observable.
var item = new ko.validatedObservable(new Tag({}));
I am then able to call:
item().isValid(); //Returns false in this case because Tag is empty
Tag looks like this
Model.Tag = function (data) {
var
Id = ko.observable(data.Id),
Name = ko.observable(data.Name).extend({ required: true, maxLength: 64 }),
Description = ko.observable(data.Description).extend({ required: true, maxLength: 512 });
return {
Id: Id,
Name: Name,
Description: Description
};
};
The issue is if I wanted to get a new tag from the server and then modify that tag..
$.ajax({
url: API + "/" + id,
type: 'GET',
dataType: 'json',
timeout: Timeout,
statusCode: {
200: function(response) { item(response); }, //Here is where the bug is!
404: ItemNotFound
},
error: function () {
Item(new Type({}));
}
});
item now contains the value from the server, however, when I run
item().isValid(); //False is returned
This is listed as bug #209 on the GitHub project https://github.com/ericmbarnard/Knockout-Validation/issues?state=open.
Does anyone know of an elegant work around? Or of another plugin that will accomplish this goal?
I don't know how elegant it is, and maybe this is not the best solution (or not a solution at all) so use it at your own risk.
But you can override the ko.validatedObservable with a "fixed" version:
ko.validatedObservable = function (initialValue) {
if (!ko.validation.utils.isObject(initialValue)) {
return ko.observable(initialValue).extend({ validatable: true });
}
var obsv = ko.observable(initialValue);
obsv.lastErrors = ko.observable(ko.validation.group(initialValue));
obsv.subscribe(function(newValue){
obsv.lastErrors(ko.validation.group(newValue));
});
obsv.errors = function() {
return obsv.lastErrors()();
};
obsv.isValid = ko.computed(function () {
return obsv.errors().length === 0;
});
return obsv;
};
My fix stores the result of the ko.validation.group call and recalculates it when the underlying obsv observable changes and I've also changed the original errors property to use the lastErrors property.
I've update the sample from the github issue you check in this demo JSFiddle.

Handling objects and routes with MVC3/Razor?

I have a geo collection that contains items like:
[state name]
[city], [state]
[country]
A text box is available for a user to begin typing, and a jQuery autocomplete box fills displays possible options.
The URL structure of the post request will depend on which was selected from the collection above, ie
www.mysite.com/allstates/someterms (if a country is selected)
www.mysite.com/city-state/someterms (if a city, state is selected)
www.mysite.com/[state name]/someterms (if a state is selected)
These are already defined in my routes.
I was initially going to add some logic on the controller to determine the appropriate URL structure, but I was thinking to simply add that as an additional field in the geo table, so it would be a property of the geo collection.
Here is my jQuery function to display the collection details when, fired on keypress in the textbox:
$(function () {
$("#txtGeoLocation").autocomplete(txtGeoLocation, {
source: function (request, response) {
$.ajax({
url: "/home/FindLocations", type: "POST",
dataType: "json",
selectFirst: true,
autoFill: true,
mustMatch: true,
data: { searchText: request.term, maxResults: 10 },
success: function (data) {
response($.map(data, function (item) {
return { label: item.GeoDisplay, value: item.GeoDisplay, id: item.GeoID }
}))
}
})
},
select: function (event, ui) {
alert(ui.item ? ("You picked '" + ui.item.label + "' with an ID of " + ui.item.id)
: "Nothing selected, input was " + this.value);
document.getElementById("hidLocation").value = ui.item.id;
}
});
});
What I would like is to have structure the URL based on an object parameter (seems the simplest). I can only seem to read the parameters on "selected", and not on button click.
How can I accomplish this?
Thanks.
To resolve this, I removed the select: portion from the Javascript, and added the selected object parameters in the MVC route sent to my controller.

Resources