Using AngularJs $resource and jquery bind - asp.net

I'm new to Angualrjs and I'm trying to figure out this code... this is how the service looks like
var userGroupServices = angular.module('userGroupServices', ['ngResource']);
userGroupServices.factory('UserRoles', ['$resource', function ($resource) {
var r1 = $resource('/api/UserRoles/:UserRoleId', null, {
'update': { method: 'PUT' },
'delete': { method: 'DELETE' }
});
r2 = $resource('/api/UserRoles', null, {
'add': { method: 'POST' },
'getRoles': { method: 'GET' }
});
r3 = $resource('/api/UserRoles/GetRolesByGroupType/:groupTypeName', null, {
'getRolesByName': {method:'GET'}
});
r1.getAll = r2.getRoles.bind(r2);
r1.add = r2.add.bind(r2);
r1.getRolesByName = r3.getRolesByName.bind(r3);
return r1;
}]);
Why is it in the end, you bind r2 and r3 variables into r1 variable? how do i use this factory to POST something, i try to post it like this way but it didn't do anything(in my controller)...
addService.addRole({ roleName: groupTypeName });

I think the reason why resources 2 and 3 are being combined and returned by resource 1 is to abstract these other resources away from someone who wants to use the UserRoles service. Now you don't need to know about how many resources the service needs in order to work.
As for posting, .addRole() doesn't seem to exist in your service. Try UserRoles.add({object}).

Related

Why is data set with Meteor Iron Router not available in the template rendered callback?

This is a bit puzzling to me. I set data in the router (which I'm using very simply intentionally at this stage of my project), as follows :
Router.route('/groups/:_id',function() {
this.render('groupPage', {
data : function() {
return Groups.findOne({_id : this.params._id});
}
}, { sort : {time: -1} } );
});
The data you would expect, is now available in the template helpers, but if I have a look at 'this' in the rendered function its null
Template.groupPage.rendered = function() {
console.log(this);
};
I'd love to understand why (presuming its an expected result), or If its something I'm doing / not doing that causes this?
From my experience, this isn't uncommon. Below is how I handle it in my routes.
From what I understand, the template gets rendered client-side while the client is subscribing, so the null is actually what data is available.
Once the client recieves data from the subscription (server), it is added to the collection which causes the template to re-render.
Below is the pattern I use for routes. Notice the if(!this.ready()) return;
which handles the no data situation.
Router.route('landing', {
path: '/b/:b/:brandId/:template',
onAfterAction: function() {
if (this.title) document.title = this.title;
},
data: function() {
if(!this.ready()) return;
var brand = Brands.findOne(this.params.brandId);
if (!brand) return false;
this.title = brand.title;
return brand;
},
waitOn: function() {
return [
Meteor.subscribe('landingPageByBrandId', this.params.brandId),
Meteor.subscribe('myProfile'), // For verification
];
},
});
Issue
I was experiencing this myself today. I believe that there is a race condition between the Template.rendered callback and the iron router data function. I have since raised a question as an IronRouter issue on github to deal with the core issue.
In the meantime, workarounds:
Option 1: Wrap your code in a window.setTimeout()
Template.groupPage.rendered = function() {
var data_context = this.data;
window.setTimeout(function() {
console.log(data_context);
}, 100);
};
Option 2: Wrap your code in a this.autorun()
Template.groupPage.rendered = function() {
var data_context = this.data;
this.autorun(function() {
console.log(data_context);
});
};
Note: in this option, the function will run every time that the template's data context changes! The autorun will be destroyed along with the template though, unlike Tracker.autorun calls.

Meteor Easy Search Package Custom Mongo Selector Query

I'm using the following package in my project - https://github.com/matteodem/meteor-easy-search
Has anyone used it and was able to set custom mongo selectors for the query parameter? The leaderboard example isn't very clear to me. I need to be able to pass meteor user id to:
EasySearch.createSearchIndex('producers', {
'collection': Producers,
'field': ['name', 'producerIdNumber', 'blocksCount', 'totalHectares', 'totalArea'],
'limit': 8,
'use' : 'mongo-db',
'sort': function() {
return { 'created': -1, 'name': -1 };
},
'query': function() {
var selector = {};
return selector
}
});
How can pass or get the meteor user id? EasySearch.createSearchIndex function runs on both server and client.
I don't have the answer to your problem - but I may be able to point you in the right direction. If you are using the meteor-accounts package, and you need to pull the user ID out of the Meteor.users() collection - you first have to publish your users.
On the server-code ->
Meteor.publish(null, function() {
return Meteor.users.find({}, {
fields: {
username: 1,
profile: 1
}
});
});
on the client, you should be able to return Meteor.users.find() or findOne() to get a userId. not the complete answer but may help?
I was able to do this like so
'query': function(searchString, opts) {
// Default query that will be used for the mongo-db selector
var query = EasySearch.getSearcher(this.use).defaultQuery(this, searchString);
if (this.props.formName != '') {
query.formName = this.props.formName;
}
if (this.props.producerId != '') {
query.producerId = this.props.producerId;
}
if (this.props.blockUnitCodeSubCode != '') {
query.blockUnitCodeSubCode = this.props.blockUnitCodeSubCode;
}
if (this.props.created.length != 0) {
query.created = {$gte:new Date(this.props.created[0]), $lt:new Date(this.props.created[1])};
}

calling one of multiple services in angularJS $resource

Is there anything wrong with this code where I am trying to have one service method point to different restful services?
var phonecatServices = angular.module('phonecatServices', ['ngResource']);
phonecatServices.factory('Phone', ['$resource',
function ($resource) {
return {
pList: $resource('/:url/:phoneId.json.htm', {}, {
query: { method: 'GET', params: { url: 'MyAngularScripts', phoneId: 'jsonPhonedata' }, isArray: true }
}),
pDetail: $resource('/Content/PhonesData/:phoneId.json.htm', {}, {
query: { method: 'GET', params: { phoneId: $routeParams.phoneId }, isArray: false }
})
};
}]);
Then in my controller I call the pList like this:
$scope.phones = Phone.pList.query();
The service method doesnt get called with any of the code above. However if I change the service to this:
var phonecatServices = angular.module('phonecatServices', ['ngResource']);
phonecatServices.factory('Phone', ['$resource',
function ($resource) {
return $resource('/:url/:phoneId.json.htm', {}, {
query: { method: 'GET', params: { url: 'MyAngularScripts', phoneId: 'jsonPhonedata' }, isArray: true }
});
}]);
and call from the controller like this:
$scope.phones = Phone.query();
IT works. What is wrong with the service where I have multiple restful calls declared? SOmething wrong with the way its configured or the way I am calling it?
The 1st approach should be working fine as well.
The only oroblem is that you are trying to access a property of $routeParams, without first injecting it via DI, thus resulting in an Error being thrown.
If you correct this, everything should work as expected.

Get /collection/id in backbone without loading the entire collection

Is there a way to load a single entity of a Backbone collection (from the server)?
Backbone.Collection.extend({
url: '/rest/product'
});
The following code can load the entire collection with a collection.fetch() but how to load a single model? Backbone's documentation says clearly that GET can be done /collection[/id] but not how.
The model has to be declared that way:
Backbone.Model.extend({
url: function() {
return '/rest/product/'+this.id;
}
});
Using it is simple as:
var model = new ProductModel();
model.id = productId;
model.fetch({ success: function(data) { alert(JSON.stringify(data))}});
While we set
url:"api/user"
for the collection, the equivalent for the model is
urlRoot:"api/user"
this will make backbone automatically append the /id when you fetch()
collection.fetch( {data: { id:56 } } )
I did this:
Catalog.Categories.Collection = Backbone.Collection.extend({
fetchOne : function (id, success) {
var result = this.get(id);
if (typeof result !== 'undefined') {
console.log(result, 'result')
success.apply(result);
return;
}
var where = {};
where[this.model.prototype.idAttribute] = id;
var model = new this.model(where);
this.add(model);
console.log(this._idAttr, where, this.model)
model.fetch({success: function () {
success.apply(model);
}});
}
};
Now call it:
collection.fetchOne(id, function () {console.log(this)});
No more guessing if the model is already in the collection!. However, you have to use a call back as you can't depend on an intimidate result. You could use async false to get around this limitation.
just .fetch a Model.
So create a model with it's own .url function.
Something like
function url() {
return "/test/product/" + this.id;
}
I did this:
var Product = Backbone.Model.extend({});
var Products = Backbone.Collection.extend({
model: Product,
url: '/rest/product'
});
var products = new Products();
var first = new Product({id:1});
first.collection = products;
first.fetch();
This has the advantage of working when you're not using a REST storage engine (instead, using something like the HTML5 Local storage, or so forth)

Persisting json data in jstree through postback via asp:hiddenfield

I've been pouring over this for hours and I've yet to make much headway so I was hoping one of the wonderful denizens of SO could help me out. Here's the problem...
I'm implementing a tree via the jstree plugin for jQuery. I'm pulling the data with which I populate the tree programatically from our webapp via json dumped into an asp:HiddenField, basically like this:
JavaScriptSerializer serializer = new JavaScriptSerializer();
string json = serializer.Serialize(Items);
json = json.ToLower();
data.Value = json;
Then, the tree pulls the json from the hidden field to build itself. This works perfectly fine up until I try to persist data for which nodes are selected/opened. To simplify my problem I've hardcoded some json data into the tree and attempted to use the cookie plugin to persist the tree state data. This does not work for whatever reason. I've seen other issues where people need to load the plugins in a specific order, etc, this did not solve my issue. I tried the same setup with html_data and it works perfectly. With this working persistence I converted the cookie plugin to persist the data in a different asp:hiddenfield (we can't use cookies for this type of thing in our application.)
essentially the cookie operations are identical, it just saves the array of nodes as the value of a hidden field. This works with the html_data, still not with the json and I have yet to be able to put my finger on where it's failing.
This is the jQuery.cookie.js replacement:
jQuery.persist = function(name, value) {
if (typeof value != 'undefined') { // name and value given, set persist
if (value === null) {
value = '';
}
jQuery('#' + name).attr('value', value);
} else { // only name given, get value
var persistValue = null;
persistValue = jQuery('#' + name).attr('value');
return persistValue;
}
};
The jstree.cookie.js code is identical save for a few variable name changes.
And this is my tree:
$(function() {
$("#demo1").jstree({
"json_data": {
"data" : [
{
"data" : "A node",
"children" : [ "Child 1", "Child 2" ]
},
{
"attr": { "id": "li.node.id" },
"data" : {
"title": "li.node.id",
"attr": { "href": "#" }
},
"children": ["Child 1", "Child 2"]
}
]
},
"persistence": {
"save_opened": "<%= open.ClientID %>",
"save_selected": "<%= select.ClientID %>",
"auto_save": true
},
"plugins": ["themes", "ui", "persistence", "json_data"]
});
});
The data -is- being stored appropriately in the hiddenfields, the problem occurs on a postback, it does not reopen the nodes. Any help would be greatly appreciated.
After looking through this some more, I just wanted to explain that it appears to me that the issue is that the tree has not yet been built from the JSON_data when the persistence operations are being attempted. Is there any way to postpone these actions until after the tree is fully loaded?
If anyone is still attempting to perform the same type of operation on a jsTree version 3.0+ there is an easier way to accomplish the same type of functionality, without editing any of the jsTree's core JavaScript, and without relying on the "state" plugin (Version 1.0 - "Persistence"):
var jsTreeControl = $("#jsTreeControl");
//Can be a "asp:HiddenField"
var stateJSONControl = $("#stateJSONControl");
var url = "exampleURL";
jsTreeControl.jstree({
'core': {
"data": function (node, cb) {
var thisVar = this;
//On the initial load, if the "state" already exists in the hidden value
//then simply use that rather than make a AJAX call
if (stateJSONControl.val() !== "" && node.id === "#") {
cb.call(thisVar, { d: JSON.parse(stateJSONControl.val()) });
}
else {
$.ajax({
type: "POST",
url: url,
async: true,
success: function (json) {
cb.call(thisVar, json);
},
contentType: "application/json; charset=utf-8",
dataType: "json"
}).responseText;
}
}
}
});
//If the user changes the jsTree, save the full JSON of the jsTree into the hidden value,
//this will then be restored on postback by the "data" function in the jsTree decleration
jsTreeControl.on("changed.jstree", function (e, data) {
if (typeof (data.node) != 'undefined') {
stateJSONControl.val(JSON.stringify(jsTreeControl.jstree(true).get_json()));
}
});
This code will create a jsTree and save it's "state" into a hidden value, then upon postback when the jsTree is recreated, it will use its old "state" restored from the "HiddenField" rather than make a new AJAX call and lose the expansions/selections that the user has made.
Got it working properly with JSON data. I had to edit the "reopen" and "reselect" functions inside jstree itself.
Here's the new functioning reopen function for anyone who needs it.
reopen: function(is_callback) {
var _this = this,
done = true,
current = [],
remaining = [];
if (!is_callback) { this.data.core.reopen = false; this.data.core.refreshing = true; }
if (this.data.core.to_open.length) {
$.each(this.data.core.to_open, function(i, val) {
val = val.replace(/^#/, "")
if (val == "#") { return true; }
if ($(("li[id=" + val + "]")).length && $(("li[id=" + val + "]")).is(".jstree-closed")) { current.push($(("li[id=" + val + "]"))); }
else { remaining.push(val); }
});
if (current.length) {
this.data.core.to_open = remaining;
$.each(current, function(i, val) {
_this.open_node(val, function() { _this.reopen(true); }, true);
});
done = false;
}
}
if (done) {
// TODO: find a more elegant approach to syncronizing returning requests
if (this.data.core.reopen) { clearTimeout(this.data.core.reopen); }
this.data.core.reopen = setTimeout(function() { _this.__callback({}, _this); }, 50);
this.data.core.refreshing = false;
}
},
The problem was that it was trying to find the element by a custom attribute. It was just pushing these strings into the array to search when it was expecting node objects. Using this line
if ($(("li[id=" + val + "]")).length && $(("li[id=" + val + "]")).is(".jstree-closed")) { current.push($(("li[id=" + val + "]"))); }
instead of
if ($(val).length && $(val).is(".jstree-closed")) { current.push(val); }
was all it took. Using a similar process I was able to persist the selected nodes this way as well.
Hope this is of help to someone.

Resources