I have articles which i'm getting from my API. My API lists them correctly when i go to http://localhost:60367/api/article/ and gets the correct data correctly for a single item when i go to http://localhost:60367/api/article/1
Using angular, how get the data for one of these articles by it's id so that if i go to my angular app and click to http://localhost:60300/perspectives/1/ I get the data of that one item. ( fyi, When i go to the index http://localhost:60300/perspectives/ I get the data accordingly. )
Please assist, my app.js file is below:
var url = "http://localhost:60367/api/article";
var modules = ['ngRoute', 'ngSanitize'];
var App = angular.module("App", modules);
// Route providers
App.config(function ($routeProvider, $locationProvider) {
$routeProvider
// Get route for perspectives homepage
.when('/', {templateUrl: 'partials/articles-home.html',
controller: ArticleController})
// Get route for perspectives single page
.when("/:id/", {templateUrl: 'partials/articles-single.html',
controller: ArticleController})
.otherwise({ redirectTo : "/"})
// Use the HTML5 History API
$locationProvider.html5Mode({ enabled: true, requireBase: false});
});
// Controller
var ArticleController = function ($scope, $http, $log) {
// For onsuccess, also do console.log for $log property
var onSuccess = function (response) {$scope.articles = response.data;
$log.info(response);};
var onFailure = function (reason) {$scope.error =
reason;$log.info(reason);};
// Get all students and display them in index
var getAllArticles = function () {$http.get(url).then(onSuccess,
onFailure)};
getAllArticles();
// Get single student by Id
//
//
};
App.controller("ArticleController", ArticleController);
SOLUTION:
Ok this is how I solved it, I created a new controller for the single item and wrote it manually like this:
var SingleArticleController = function ($scope, $http, $routeParams) {
$http({
url: "http://localhost:60367/api/article/{id}",
params: { id: $routeParams.id },
method: "get"
})
.then(function (response) {
$scope.article = response.data;
});
};
You'll want to use $routeParams:
What I've outline here will allow you to use the same controller here as that's what you've show in your config. Often-times, you'd assign a separate controller in your route (something like ArticleController, ArticleListController.). If you do that, the same process applies, but you wouldn't need to check if you have an ID parameter.
In your Controller:
// Add $routeParams
.controller('ArticleController', function($scope, $routeParams) {
// Get the id
var id = $routeParams.id;
// Set url based on whether or not you have an ID
var fullUrl = id ? url + '/' + id : url;
var getAllArticles = function() {
$http.get(fullUrl).then(onSuccess,
onFailure)
};
})
Related
I have a search page , once user clicks Search button it calls an angualrjs function, where I need to update some $scope variables and redirect to another page.
This is my service to share the object between controllers
var app = angular.module('MyApp', ['angular.filter', 'googlechart']);
app.factory('sharedService', function () {
var testObj = {
name:'User Name 1',
age: 25
};
var searchParameter = function (newObj) {
testObj = newObj;
};
var getParameter = function () {
return testObj;
};
return {
searchParameter: searchParameter,
getParameter: getParameter
};
});
Here is the Controller 1 : SearchController
app.controller('SearchController', function ($scope, $parse, $filter, $location, $window, sharedService) {
$scope.searchParameter = function (searchParameter) {
var testObj = {
name: 'UserName 2',
age: 35
};
sharedService.searchParameter(testObj);
$window.location.href = 'http://localhost:8080/UI/SearchResult.aspx';
}
});
And this is my controller 2 : ResultController
app.controller('ResultController', function ($scope, $parse, $filter, sharedService) {
$scope.getParameter = function () {
$scope.testParam = sharedService.getParameter();
}
});
testObj is a model.
It is redirecting to the result page, but the testObj value is not getting updated to UserName 2.
How can I get updated value in the controller 2?
This is not working because in your service, the object is declared as var. So even if you're updating from outside, it will not return the value.
Also apart from service, if your pages are like parent-child controller, you can share objects between controller. Let me know if service solution is not working, I can share solution for sharing objects between controllers.
The variable should be bound to the service. Something like below:
var app = angular.module('MyApp', ['angular.filter', 'googlechart']);
app.factory('sharedService', function () {
this.testObj = {
name:'User Name 1',
age: 25
};
var searchParameter = function (newObj) {
this.testObj = newObj;
};
var getParameter = function () {
return this.testObj;
};
return {
searchParameter: searchParameter,
getParameter: getParameter
};
});
I cannot seem to find any documentation that will explain how I can get the filename and filepath of an uploaded collectionFS image into my meteor method.
I am able to get the image URL on the client side no problem using helpers, but I cannot seem to figure out how I can send the filename and filepath of the attached image to my method.
Method JS
Meteor.methods({
addQuote: function(data) {
check(data, Object);
var attachments = [];
var html = html;
// need to get the filename and filepath from collectionFS
// I would then have the data go here
attachments.push({filename: , filePath: });
this.unblock();
var email = {
from: data.contactEmail,
to: Meteor.settings.contactForm.emailTo,
subject: Meteor.settings.contactForm.quoteSubject,
html: html,
attachmentOptions: attachments
};
EmailAtt.send(email);
}
});
Controller JS
function ($scope, $reactive, $meteor) {
$reactive(this).attach($scope);
this.user = {};
this.helpers({
images: () => {
return Images.find({});
}
});
this.subscribe('images');
this.addNewSubscriber = function() {
// Uploads the Image to Collection
if(File.length > 0) {
Images.insert(this.user.contactAttachment);
console.log(this.user.contactAttachment);
}
// This is the variable I use to push to my method
// I image I need to push the filename and filepath also
// I am unsure how to access that information in the controller.
var data = ({
contactEmail: this.user.contactEmail,
contactName: this.user.contactName,
contactPhone: this.user.contactPhone,
contactMessage: this.user.contactMessage
});
// This will push the data to my meteor method "addQuote"
$meteor.call('addQuote', data).then(
function(data){
// Show Success
},
function(err) {
// Show Error
}
);
};
You can use the insert callback to get this informations:
Images.insert(fsFile, function (error, fileObj)
{
if (error) console.log(error);
else
{
console.log(fileObj);
//Use fileObj.url({brokenIsFine: true}); to get the url
}
});
I have a meteor project where all my users have their own profile page setup in this way using routes:
Routes code:
Router.route('/#:username', {
name: 'profile',
controller: 'ProfileController'
});
ProfileController = RouteController.extend({
template: 'profile',
waitOn: function() {
return Meteor.subscribe('userProfile', this.params.username);
},
data: function() {
var username = Router.current().params.username;
return Meteor.users.findOne({
username: username
});
}
});
Server code:
Meteor.publish('users', function() {
return Meteor.users.find({}, {fields: {username: 1, emails: 1, profile: 1, roles: 1}});
});
Meteor.publish('userProfile', function(username) {
// Try to find the user by username
var user = Meteor.users.findOne({
username: username
});
// If we can't find it, mark the subscription as ready and quit
if (!user) {
this.ready();
return;
}
// If the user we want to display the profile is the currently logged in user
if(this.userId === user._id) {
// Then we return the curresonding full document via a cursor
return Meteor.users.find(this.userId);
} else {
return Meteor.users.find(user._id, {
fields: {
profile: 0
}
});
}
});
I want to do something similar with a pages collection that I've set up. Creating the collection works and the collection page has an _id field that is made upon creation.
Right now the program works nicely for users where mysite.com/# works. Now I want the same thing to work for mysite.com/&
I've basically attempted to do the exact same thing as I did in the above code with the user name but it wasn't working. I've checked to make sure my creation of the collection items are working and they are. But somehow I can't figure out how to do this same thing with collections since I'm relatively new to using routes.
This is what I've attempted:
Here's my routes:
var pageRoute = '/&:_id';
Router.route(pageRoute, {
name: 'page',
controller: 'PageController'
});
PageController = RouteController.extend({
template: 'page',
waitOn: function() {
return Meteor.subscribe('Page', this.params._id);
},
data: function() {
var _id = Router.current().params._id;
return Meteor.pages.findOne({
_id: _id
});
}
});
Server code:
Meteor.publish('pages', function() {
return Pages.find({});
});
Meteor.publish('Page', function(_id) {
// Try find the page by _id
var page = Meteor.pages.findOne({
_id: _id
});
// If we can't find it, mark the subscription as ready and quit
if (!page) {
this.ready();
return;
}
// If the page we want to display is not claimed, display it
if(true) {
return Meteor.pages.find(this._id);
} else {
// Redirect to the page
}
});
The Schema of the Page Collection:
_id: ,
createdAt: ,
CreatedBy: ,
claimedAt: ,
claimedBy: ,
Update:
I've scoped it down to this problem, I get the following error in the console server-side:
I20160202-11:16:24.644(2)? Exception from sub qrPage id 2kY6RKCTuCpBDbuzm TypeError: Cannot call method 'findOne' of undefined
I20160202-11:16:24.645(2)? at [object Object].process.env.MAIL_URL [as _handler] (server/ecclesia.life_server.js:40:33)
I20160202-11:16:24.645(2)? at maybeAuditArgumentChecks (livedata_server.js:1698:12)
I20160202-11:16:24.645(2)? at [object Object]._.extend._runHandler (livedata_server.js:1023:17)
I20160202-11:16:24.645(2)? at [object Object]._.extend._startSubscription (livedata_server.js:842:9)
I20160202-11:16:24.646(2)? at [object Object]._.extend.protocol_handlers.sub (livedata_server.js:614:12)
I20160202-11:16:24.646(2)? at livedata_server.js:548:43
This error occurs whenever I try to direct to mysite.com/&<_id>
Based on this website: https://perishablepress.com/stop-using-unsafe-characters-in-urls/
It looks like # is considered an unsafe character to use in a URL string. On the web page above, it looks like there are several symbols you could use instead as safe characters.
I just tried this on my own machine, and I don't think Meteor plays nicely when the # is introduced in the URL.
This got it working...
Publications:
Meteor.publish('qrpages', function() {
return QRPages.find({});
});
Meteor.publish('qrPage', function(id) {
// Try find the qrpage by _id
var qrpage = QRPages.find({_id: id});
// If we can't find it, mark the subscription as ready and quit
if (!qrpage) {
this.ready();
return;
}
return qrpage;
});
Routes:
var qrpageRoute = '/$:_id';
Router.route(qrpageRoute, {
name: 'qrpage',
controller: 'QRController'
});
QRController = RouteController.extend({
template: 'qrpage',
waitOn: function() {
var id = this.params._id;
return Meteor.subscribe('qrPage', id);
},
data: function() {
var id = this.params._id;
return QRPages.findOne({
_id: id
});
}
});
My brain is hurting because of all the inconsistency. Please have a look at the code below and correct/complete it:
Template.Example.events({
'click #example': function(event, template) {
instance = template; // or = Template.instance();
instance_reactive_data_context = template.currentData(); // or = Template.currentData();
instance_nonreactive_data_context = ???
event_data_context = event.currentTarget;
});
Template.Example.helpers({
example: function() {
instance = Template.instance();
instance_reactive_data_context = this; // or = Template.currentData();
instance_nonreactive_data_context = ???
}
});
Template.Example.onCreated(function () {
instance = this;
instance_reactive_data_context = this.currentData();
instance_nonreactive_data_context = this.data;
});
Here's the answer, which even shows a bit more. It includes creating and accessing a reactive-var or reactive-dictionaries attached to the template. All this is extremely important to understand for Meteor developers:
Template.Example.onCreated(function () {
instance = this; // or = Template.instance();
// instance_reactive_data_context = no point in having a reactive data context since this function is only executed once
instance_nonreactive_data_context = this.data;
// now in order to attach a reactive variable to the template:
let varInitialValue = ...
instance.reactive_variable = new ReactiveVar(varInitialValue);
// and now let's attach two reactive dictionaries to the template:
let dictInitialValue_1 = { ... }
let dictInitialValue_2 = [ ... ]
instance.reactive_dictionaries = new ReactiveDict();
instance.reactive_dictionaries.set('attachedDict_1', dictInitialValue_1);
instance.reactive_dictionaries.set('attachedDict_2', dictInitialValue_2);
});
Template.Example.events({
'click #example': function(event, template) {
instance = template; // or = Template.instance();
instance_reactive_data_context = Template.currentData();
instance_nonreactive_data_context = template.data;
event_data_context = event.currentTarget;
// to access or modify the reactive-var attached to the template:
console.log(template.reactive_variable.get());
template.reactive_variable.set('new value');
// to access or modify one of the reactive-dictionaries attached to the template:
console.log(template.reactive_dictionaries.get('attachedDict_2'));
template.reactive_dictionaries.set('attachedDict_2', { newkey: 'new value', somearray: ['a', 'b'] });
});
Template.Example.helpers({
example: function() {
instance = Template.instance();
instance_reactive_data_context = this; // or = Template.currentData();
// instance_nonreactive_data_context = it can't be accessed as a non-reactive source. When you'll need something like this, most likely because the helper is running too many times, look into the [meteor-computed-field][1] package
// to access or modify the reactive-var attached to the template:
console.log(Template.instance().reactive_variable.get());
Template.instance().reactive_variable.set('new value');
// to access or modify one of the reactive-dictionaries attached to the template:
console.log(Template.instance().reactive_dictionaries.get('attachedDict_2'));
Template.instance().reactive_dictionaries.set('attachedDict_2', 'new value here');
// obviously since you declared instance on the first line, you'd actually use everywhere "instance." instead of "Template.instance()."
}
});
The following code does not update the database everytime a tweet is found - it silently hangs, adding no tweets to the database.
If a tweet is manually added to the DB from the JS console in the browser, it shows up just fine, but no tweets are being added to the DB automatically.
Tweets = new Meteor.Collection("tweets");
if (Meteor.isClient) {
Template.kildeer.tweets = function () {
return Tweets.find({});
};
}
if (Meteor.isServer) {
Meteor.startup(function () {
var require = __meteor_bootstrap__.require,
Twit = require('twit')
, T = new Twit({
consumer_key: 'blahblah',
consumer_secret: 'blahblah',
access_token: 'blahblah',
access_token_secret: 'blahblah'
});
var stream = T.stream('statuses/filter', { track: ['bing', 'google', 'microsoft'] })
stream.on('tweet', function (tweerp) {
var id;
console.log(tweerp.text);
id = Tweets.insert({text: tweerp.text, screen_name: tweerp.user.screen_name, profile_image: tweerp.user.profile_image_url});
console.log(id);
});
});
}
In Meteor, Collection.insert must always be called inside of a Fiber() closure.
Fiber(function() {
Tweets.insert({text: tweerp.text, screen_name: tweerp.user.screen_name, profile_image: tweerp.user.profile_image_url});
}).run();