Rectangle 27 16

This example demonstrates the proper structure of an angular app:

  • Implementation of a service singleton, and injection into your controller
  • Use of $http promises to invoke web API calls asynchronously and allowing callers of your service to handle their success/failure.
  • Use of "controller as" syntax way of exposing functions from your controller rather than exposing functions directly from scope.
angular.module('recipeapp')
  .controller('recipeCtrl', ['$scope', 'recipeService',
    function($scope, recipeService){
      // initialize your model in you controller
      $scope.recipe={};

      // declare a controller function that delegates to your service to save the recipe
      this.saveRecipe = function(recipe) {
           // call the service, handle success/failure from within your controller
           recipeService.saveRecipe(recipe).success(function() { 
               alert('saved successfully!!!'); 
           }).error(function(){
               alert('something went wrong!!!');
           });

      }
  }]);

In your recipe service, define the saveRecipe function:

angular.module('recipeapp').service('recipeService',['$http', function($http){

  // expose a saveRecipe function from your service
  // that takes a recipe object
  this.saveRecipe = function(recipe){
      // return a Promise object so that the caller can handle success/failure
      return $http({ method: 'POST', url: '/api/recipe/add', data: recipe});
  }

}]);

Bind your recipe object to your view; add a button to invoke the saveRecipe controller function and save the recipe (passing in the model recipe object):

<div ng-app="recipeapp" ng-controller="recipeCtrl as ctrl">
   <form name="recipeForm">
    Recipe Name: <input type="text" ng-model="recipe.name" />
    <button ng-click="ctrl.saveRecipe(recipe)">Save Recipe</button>
    </form>
</div>
angular

AngularJS : passing params from controller to service - Stack Overflow

angularjs angularjs-scope angularjs-service angularjs-controller
Rectangle 27 1

var module = angular.module('example.service', []);


module.services('ExampleServices', ['$http', '$q', function ($http,
$q) {

    var resourceUrl;

    return {


        setResourceUrl: function(resourceUrl) {
            this.resourceUrl = resourceUrl;
        },



        create: function(params) {
            //access params here sent from controller 
           //make call to server using $http 
           //return back the promise or response
        },



        remove: function(id) {
            //access id here sent from controller 
           //make call to server using $http 
           //return back the promise or response
        }

}
ExampleServices.create(params)

params could be any object, most probably data captured using forms.

ExampleServices.remove(id)

id could be primary id of the record to be removed from database.

AngularJS : passing params from controller to service - Stack Overflow

angularjs angularjs-scope angularjs-service angularjs-controller
Rectangle 27 1

Controllers are not shared between pages - a new instance is created each time the controller is used. You should not expect to be able to share data from a controller with anything outside the scope of that controller either. If you need to share data between pages or controllers, you should use a service or "value" object to maintain that state. Another option would be passing the data between the pages using the state params:

ui-sref="tab.count({ input: input })"

Note that Ionic uses the Angular UI Router project for its navigation logic, so the documentation there also applies to using Ionic.

For the ui-sref code in this answer, I'm assuming I need to modify the state params. Could you expand the answer on how to do this? I'm new to AngularJS and Ionic.

See the example in my answer - the object in the ui-sref directive will be passed to the tab.count page, and you'll be able to get those values from the $stateParams service, which can be injected into the controller. Ionic uses Angular UI Router for its navigation, so you can just use their documentation for reference: github.com/angular-ui/ui-router/wiki

This was not what I was hoping for but it is on-point. I ended up just adding some parameters to the routing. .state('tab.firstTab', { url: "/details?parentID&field2" ... Thanks for the answer.

AngularJS $scope values from ng-model lost from page to page in same c...

angularjs angularjs-scope ionic-framework ionic angular-ngmodel
Rectangle 27 44

The best practise would be to abstract the $http call out into a 'service' that provides data to your controller:

module.factory('WidgetData', function($http){
    return {
        get : function(params){
            return $http.get('url/to/widget/data', {
                params : params
            });
        }
    }
});

module.controller('WidgetController', function(WidgetData){
    WidgetData.get({
        id : '0'
    }).then(function(response){
        //Do what you will with the data.
    })
});

Abstracting the $http call like this will allow you to reuse this code across multiple controllers. This becomes necessary when the code that interacts with this data becomes more complex, perhaps you wish to process the data before using it in your controller, and cache the result of that process so you won't have to spend time re-processing it.

You should think of the 'service' as a representation (or Model) of data your application can use.

angularjs - What is the best practice for making an AJAX call in Angul...

angularjs
Rectangle 27 44

The best practise would be to abstract the $http call out into a 'service' that provides data to your controller:

module.factory('WidgetData', function($http){
    return {
        get : function(params){
            return $http.get('url/to/widget/data', {
                params : params
            });
        }
    }
});

module.controller('WidgetController', function(WidgetData){
    WidgetData.get({
        id : '0'
    }).then(function(response){
        //Do what you will with the data.
    })
});

Abstracting the $http call like this will allow you to reuse this code across multiple controllers. This becomes necessary when the code that interacts with this data becomes more complex, perhaps you wish to process the data before using it in your controller, and cache the result of that process so you won't have to spend time re-processing it.

You should think of the 'service' as a representation (or Model) of data your application can use.

angularjs - What is the best practice for making an AJAX call in Angul...

angularjs
Rectangle 27 43

The best practise would be to abstract the $http call out into a 'service' that provides data to your controller:

module.factory('WidgetData', function($http){
    return {
        get : function(params){
            return $http.get('url/to/widget/data', {
                params : params
            });
        }
    }
});

module.controller('WidgetController', function(WidgetData){
    WidgetData.get({
        id : '0'
    }).then(function(response){
        //Do what you will with the data.
    })
});

Abstracting the $http call like this will allow you to reuse this code across multiple controllers. This becomes necessary when the code that interacts with this data becomes more complex, perhaps you wish to process the data before using it in your controller, and cache the result of that process so you won't have to spend time re-processing it.

You should think of the 'service' as a representation (or Model) of data your application can use.

angularjs - What is the best practice for making an AJAX call in Angul...

angularjs
Rectangle 27 2

Include the $state service in your controller. Than you can assign this service to a property on your scope.

$scope.$state = $state;

Then to get the current state in your templates:

$state.current.name
$state.includes(stateName [, params])
$state.includes('state.name', {id: 1}); // returns true

I want make it accessible throughout all the controls and html. how can i access in index.html.

can we add $scope.$state = $state; in .run method

javascript - Angular js : How to access $state current page name and p...

javascript jquery html angularjs
Rectangle 27 2

You could make your service completely unaware of the scope, but in your controller allow the scope to be updated asynchronously.

The problem you're having is because you're unaware that http calls are made asynchronously, which means you don't get a value immediately as you might. For instance,

var students = $http.get(path).then(function (resp) {
  return resp.data;
}); // then() returns a promise object, not resp.data

There's a simple way to get around this and it's to supply a callback function.

.service('StudentService', [ '$http',
    function ($http) {
    // get some data via the $http
    var path = '/students';

    //save method create a new student if not already exists
    //else update the existing object
    this.save = function (student, doneCallback) {
      $http.post(
        path, 
        {
          params: {
            student: student
          }
        }
      )
      .then(function (resp) {
        doneCallback(resp.data); // when the async http call is done, execute the callback
      });  
    }
.controller('StudentSaveController', ['$scope', 'StudentService', function ($scope, StudentService) {
  $scope.saveUser = function (user) {
    StudentService.save(user, function (data) {
      $scope.message = data; // I'm assuming data is a string error returned from your REST API
    })
  }
}]);
<div class="form-message">{{message}}</div>

<div ng-controller="StudentSaveController">
  <form novalidate class="simple-form">
    Name: <input type="text" ng-model="user.name" /><br />
    E-mail: <input type="email" ng-model="user.email" /><br />
    Gender: <input type="radio" ng-model="user.gender" value="male" />male
    <input type="radio" ng-model="user.gender" value="female" />female<br />
    <input type="button" ng-click="reset()" value="Reset" />
    <input type="submit" ng-click="saveUser(user)" value="Save" />
  </form>
</div>

This removed some of your business logic for brevity and I haven't actually tested the code, but something like this would work. The main concept is passing a callback from the controller to the service which gets called later in the future. If you're familiar with NodeJS this is the same concept.

angularjs - Injecting $scope into an angular service function() - Stac...

angularjs angular-ui angular-ui-router
Rectangle 27 3

I have a app with an authentication/authorization check in the $routeChangeStart event handler. If not authenticated, I present user with modal login page. I want a successful login to send them to their original destination (Beauty of $routeChangeStart is that it will run again and check authorization after the successful login). I save the path built from the next in a user session service that is injected into the modal login controller.

here is the event handler

//before each route change, check if the user is logged in
//and authorized to move onto the next route
$rootScope.$on('$routeChangeStart', function (event, next, prev) {
    if (next !== undefined) {
        if ('data' in next) {
            if ('authorizedRoles' in next.data) {
                var authorizedRoles = next.data.authorizedRoles;
                if (!SessionService.isAuthorized(authorizedRoles)) {
                    event.preventDefault();
                    SessionService.setRedirectOnLogin(BuildPathFromRoute(next));
                    if (SessionService.isLoggedIn()) {
                        // user is not allowed
                        $rootScope.$broadcast(AUTH_EVENTS.notAuthorized);
                    } else {
                        // user is not logged in
                        $rootScope.$broadcast(AUTH_EVENTS.notAuthenticated);
                    }
                }   
            }
        }
    }
});

Here is the function that builds the path from the next object

function BuildPathFromRoute(routeObj)
{
    var path = routeObj.$$route.originalPath;
    for (var property in routeObj.pathParams)
    {
        if (routeObj.pathParams.hasOwnProperty(property))
        {
            var regEx = new RegExp(":" + property, "gi");
            path = path.replace(regEx, routeObj.pathParams[property].toString());
        }
    }
    return path;
}
  • I'm not keen on my $$route reliance, but I couldn't find any other way to do it. Maybe I missed something easier. I may be inviting trouble in the long term.
  • Standard caveat: This is all client side and subject to abuse. Make sure authentication/authorization happens server side.
  • The next Route object (from the event handler) also has a params property. I'm not sure if I should spin through its properties like I do with pathParams.

URL from $routeChangeStart route params in angularjs routes - Stack Ov...

angularjs angularjs-routing
Rectangle 27 1

Complicated forms like this are best handled in a service object initiated in the primary resource's create or update action. This allows you to easily find where the logic is happening afterwards. In this case it looks like you can kick off your service object in your GradingsController. I also prefer formatting a lot of the data in the markup, to make the handling easier in the service object. This can be done a'la rails, by passing a name like "grade[style]" and "grade[rank]". This will format your params coming in as a convenient hash: {grade: {style: "karate", rank: "3"}}. That hash can be passed to your service object to be parsed through.

Without really grasping the full extent of your specific requirements, let's put together an example form:

<%= form_for :grading, url: gradings_path do |f| %>
  <h1><%= @rank.name %></h1>
  <%- @grades.each do |grade| %>
    <div>
      <%= hidden_field_tag "grade[#{grade.id}][id]", grade.id %>
      <%= check_box_tag "grade[#{grade.id}][active]" %>
      ...
      <%= text_field_tag "grade[#{grade.id}][date]" %>
    </div>
  <%- end %>
  <%= submit_tag %>
<%- end %>

With a form like this, you get your params coming into the controller looking something like this:

"grade"=>{
  "1"=>{"id"=>"1", "active"=>"1", "date"=>"2013-06-21"},
  "3"=>{"id"=>"3", "date"=>"2013-07-01"}
}

Nicely formatted for us to hand off to our service object. Keeping our controller nice and clean:

class GradingsController < ApplicationController

  def index
    # ...
  end

  def create
    builder = GradeBuilder.new(current_user, params['grade'])
    if builder.run
      redirect_to gradings_path
    else
      flash[:error] = 'Something went wrong!' # maybe even builder.error_message
      render :action => :index
    end
  end

end

So now we just need to put any custom logic into our builder, I'd probably recommend just making a simple ruby class in your /lib directory. It could look something like this:

class GradeBuilder

  attr_reader :data, :user

  def self.initialize(user, params={})
    @user = user
    @data = params.values.select{|param| param['active'].present? }
  end

  def run
    grades = data.each{|entry| build_grade(entry)}
    return false if grades.empty?
  end

  private

  def build_grade(entry)
    grade = Grade.find(entry['id'])
    rank = grade.rankings.create(student_id: user, date: entry['date'])
  end

end

There will obviously need a lot more work to pass all the specific data you need from the form, and extra logic in the GradeBuilder to handle edge cases, but this will give you a framework to handle this problem in a maintainable and extensible way.

Thanks for your answer, I ended up implementing something similar once I remembered I could format the hash. The service object makes everything a lot cleaner though!

ruby on rails - How to create multiple "has_many through" associations...

ruby-on-rails ruby-on-rails-3.2
Rectangle 27 2

The reason that you have trouble with testing is because your Controller class uses the Service Locator anti-pattern. A Service Locator is a either a global instance (the DependencyResolver.Current) or an abstraction that allows resolving dependencies at runtime. One of the many downsides of the Service Locator is the problems it causes with testing.

You should move away from the Service Locator pattern and use dependency injection instead, favorably constructor injection. Your application components should have a single public constructor and those constructors should do nothing more than storing the incoming dependencies. This will result in the following UsersController implementation:

public class UsersController : Controller
{
   private IUsersRepository usersRepository;
   public UsersController(IUsersRepository usersRepository)
   {
       this.usersRepository = usersRepository;
   }
   public ActionResult Index()
   {
        return View(this.usersRepository.MyRepository());
   }
}
public class UsersControllerTests
{
    [TestMethod]
    public void Index_Always_CallsRepository()
    {
        // Arrange
        var repository = new Mock<IUsersRepository>();
        var controller = CreateValidUsersController(repository.Instance);

        // Act
        var result = controller.Index();

        // Assert
        Assert.IsTrue(repository.IsCalled);
    }

    // Factory method to simplify creation of the class under test with its dependencies
    private UsersController CreateValidUsersController(params object[] deps) {
        return new UsersController(
            deps.OfType<IUsersRepository>().SingleOrDefault() ?? Fake<IUsersRepository>()
            // other dependencies here
            );
    }

    private static T Fake<T>() => (new Mock<T>()).Instance;
}

This does however, force you to change MVC's default IControllerFactory, since out-of-the-box, MVC can only handle controllers with a default constructor. But this is trivial and looks as follows:

public sealed class CompositionRoot : DefaultControllerFactory
{
    private static string connectionString = 
        ConfigurationManager.ConnectionStrings["app"].ConnectionString;

    protected override IController GetControllerInstance(RequestContext _, Type type) {

        if (type == typeof(UsersController))
            return new UsersController(new UsersRepository());

        // [other controllers here]

        return base.GetControllerInstance(_, type);
    }
}

Your new controller factory can be hooked into MVC as follows:

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start() {
        ControllerBuilder.Current.SetControllerFactory(new CompositionRoot());

        // the usual stuff here
    }
}

You can find a more complete example here.

Agreed, but most DI containers already have a (nuget) package for integrating with ASP.NET. No need to write the ControllerFactory stuff yourself.

@HenkHolterman: I don't think the OP is using a DI container.

But he should be be going to use one.

@HenkHolterman: I don't agree. A DI container isn't a required tool. It's often more valuable to start with Pure DI. (and do remember that this is the opinion of someone who maintains a DI container ;-))

c# - How can I pass a mock object when I am doing setter injection in ...

c# asp.net-mvc dependency-injection nunit moq
Rectangle 27 0

It's my understanding that you can't pass objects between states as params. One option is to use a service which is accessible by all controllers that you inject it into.

service

I have read that answer but using a controller can be a bit messy. If i need to use this data in more views i have to add a function or a nee service every time. If i can't pass objects, can i pass some attributes of the objects?

How to pass object with ui router betwenn controllers in a $state angu...

angularjs angular-ui-router
Rectangle 27 0

As you suggest using ngRoute, you could just inject the $rootParams-service into your controllers and get all the current params. If you also need the current controller selected by ngRoute, you should inject the $route-service as well. See the example in the ngRoute documentation for more details on how to use these services - or provide a (minimal) version of your angular code to give you an example based on your use case.

BTW: If you also have different views and/or layouts (for example not only video) in your SPA, you could use ngRoute's ng-view directive to set up a viewport for all these different layouts. In that way each layout can have it's own template and a layout specific controller that can reuse generic controllers and directives (for example for comments). Again I need more code to give an meaningful example for that.

AngularJS - Managing URL changes across multiple controllers / UI elem...

angularjs angularjs-directive angular-ui
Rectangle 27 0

Are you running your test as a unit or integration test? If it's not already there, try moving it into test/integration and run it from there using

grails test-app integration:

That runs the test within the Grails environment and will give the joda-time plugin the opportunity to do whatever meta programming magic it's doing to create the type conversion to DateTime it looks like you're missing.

groovy - Grails - How to - Unit test Service that uses params from con...

unit-testing groovy grails
Rectangle 27 0

var module = angular.module('example.service', []);


module.services('ExampleServices', ['$http', '$q', function ($http,
$q) {

    var resourceUrl;

    return {


        setResourceUrl: function(resourceUrl) {
            this.resourceUrl = resourceUrl;
        },



        create: function(params) {
            //access params here sent from controller 
           //make call to server using $http 
           //return back the promise or response
        },



        remove: function(id) {
            //access id here sent from controller 
           //make call to server using $http 
           //return back the promise or response
        }

}
ExampleServices.create(params)

params could be any object, most probably data captured using forms.

ExampleServices.remove(id)

id could be primary id of the record to be removed from database.

passing params from controller to service in angularjs - Stack Overflo...

angularjs angularjs-scope angularjs-service angularjs-controller
Rectangle 27 0

Controllers are not shared between pages - a new instance is created each time the controller is used. You should not expect to be able to share data from a controller with anything outside the scope of that controller either. If you need to share data between pages or controllers, you should use a service or "value" object to maintain that state. Another option would be passing the data between the pages using the state params:

ui-sref="tab.count({ input: input })"

Note that Ionic uses the Angular UI Router project for its navigation logic, so the documentation there also applies to using Ionic.

For the ui-sref code in this answer, I'm assuming I need to modify the state params. Could you expand the answer on how to do this? I'm new to AngularJS and Ionic.

See the example in my answer - the object in the ui-sref directive will be passed to the tab.count page, and you'll be able to get those values from the $stateParams service, which can be injected into the controller. Ionic uses Angular UI Router for its navigation, so you can just use their documentation for reference: github.com/angular-ui/ui-router/wiki

This was not what I was hoping for but it is on-point. I ended up just adding some parameters to the routing. .state('tab.firstTab', { url: "/details?parentID&field2" ... Thanks for the answer.

AngularJS $scope values from ng-model lost from page to page in same c...

angularjs angularjs-scope ionic-framework ionic angular-ngmodel
Rectangle 27 0

You can store theses values in a service. On your controller initialization you will just set up the controllers var with the stored var in the service.

In my opinion one of the way to go is by using the session storage to store the filters within a navigation flow into you application.

In you controller your will init the filters vars like this :

$scope.filterName = sessionStorage.filterName
//In your HTML on the filter
ng-change="onFilterNameChange()"

//In your JS
$scope.onFilterNameChange = function(){
    sessionStorage.filterName = $scope.filterName
}

If you want to be able to "clean" the filters you could also do this you could manage an optional url param (like ?resetFilters=true) that clean the filters.

You could also (if there is not that much filters) explicitly sets the filters in the URL like this

.state ('state1', {
    url: '/state1?filter1&filter2&filter3',
    views: {
        "main@": {
            controller: 'StateOneCtrl',
            templateUrl: 'folder/state1.tpl.html'
        }
    },
    ncyBreadcrumb: { label: 'State One' },
    data: { pageTitle: 'State One', showTitle: false}
})

But you may be stuck as you can't give an object to the URL (whereas you can stringify one for your sessionStorage.

what if there are 10 filter parameter? will it be good solution to pass it through url?

@PankajParkar Depends on the tastes. I'd prefer not to give 10 filter in my URL (wheras Google pretty much give all the informations in the url) If i had that much filters i would go for the sessionStorage solution.

local storage might be one way to handle this. I was also considering using a service to hold the state of the filters when the user navigated between states since my biggest issue is the controller reinitializes itself when the user clicks back to state1.

@ibtjw In my opinion sessionStorage (not localStorage) is a way to go. But the service is a really really good option too if not better.

Right, session storage not local storage. :)

angularjs - Angular UI Router states - Stack Overflow

angularjs angular-ui-router
Rectangle 27 0

The controller is not the presentation layer. Its the C in MVC. The persistence layer should only be concerned with persistence, not Model object creation. The code above is OK. Some would create the objects in the service, not in the controller, but the params are readily available in the controller so IMHO its acceptable.

Sorry my mistake calling the controller a presentation layer. I'm bit struggling with the layer stuff yet to figure out which is which. (English is not my first language)

java - Where should I create new entity - in presentation layer or not...

java presentation-layer
Rectangle 27 0

$scope.serviceList=["yearDetails","monthDetails","dayDetails"];

//controller
$scope.getDetails=function(type,index){

    if(type==$scope.serviceList[index]){

     //now i can able to call my service through injector in angular
     var $inj = angular.element('html').injector();
     var serv = $inj.get($scope.serviceList[index]);
     serv.query(function(data){
            console.log(data);
     });
    }
}

//service
.factory('yearDetails', function($resource){
           return $resource('/getyearDetails', {}, {
               query: { method:'POST', params:{}, isArray:false }
   });
})
.factory('monthDetails', function($resource){
           return $resource('/getmonthDetails', {}, {
               query: { method:'POST', params:{}, isArray:false }
   });
})
.factory('dayDetails', function($resource){
           return $resource('/getdayDetails', {}, {
               query: { method:'POST', params:{}, isArray:false }
   });
})

angularjs - How to call "Angular JS" service method using string varia...

angularjs angularjs-service
Rectangle 27 0

You need to use the $stateParams service in your controller, but having said that you also need to have the proper routing setup to grab the params with ui-router.

RTFM in the nicest possible way of course! :-)

angularjs - Angular ui router match any route get all query parameters...

angularjs angular-ui angular-routing