Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple independent partials in AngularJS

I've been working on a Angular.js tutorial that I now want to extend. It's a simple CRUD app that has a list of templates: list.html (just records in a db with a title and content), a create form: new.html, and an edit form: edit.html.

Just now list.html loads an array of templates from my REST app and displays them in a table. There is a search form and some sorting functionality.

New.html has a form for creating new templates.

These two .html files are loaded by going to different routes. #/ and #/new

What I want to do now is have one file index.html which loads both list.html inside one div and then new.html inside another div. The idea is that the list of records will always be displayed on the left and then the other partials will be loaded into the area to the right. So clicking on a template in the list will open it in the area next to the list but the list remains untouched. Then if i click the new template button the new template form will re-appear in the content area but the list will remain untouched.

Here is my code:

app.js

var MailStash = angular.module("MailStash", ["ngResource"]).
    config(function($routeProvider){
        $routeProvider.
            when('/', {controller: ListCtrl, templateUrl: '/js/partials/list.html'}).
            when('/new', {controller: CreateCtrl, templateUrl: '/js/partials/new.html'}).
            when('/edit/:editId', {controller: EditCtrl, templateUrl: '/js/partials/edit.html'})
    });

MailStash.factory('Template', function($resource){
    return $resource('/api/v1/template/:id', {id: '@id'}, { update: { method: 'PUT' } });
});

var EditCtrl = function($scope, $location, $routeParams, Template) {
    $scope.action = "Update";

    var id = $routeParams.editId;
    $scope.template = Template.get({id: id});

    $scope.save = function () {
        Template.update({id: id}, $scope.template, function () {
            $location.path('/');
        });
    };
}

var CreateCtrl = function($scope, $location, Template) {
    $scope.save = function() {
        Template.save($scope.template, function(){
            $location.path('/');
        });
    }
}

var ListCtrl = function($scope, $location, Template) {
    $scope.search = function() {
        Template.query({
            q: $scope.query,
            sort_order: $scope.sort_order, 
            is_desc: $scope.is_desc,
            offset: $scope.offset,
            limit: $scope.limit
            },
            function(data){
                $scope.more = data.length === 20;
                $scope.templates = $scope.templates.concat(data);
            });
    }

    $scope.sort = function(col) {
        if($scope.sort_order === col) {
            $scope.is_desc = !$scope.is_desc;
        } else {
            $scope.sort_order = col;
            $scope.is_desc = false;
        }

        $scope.reset();
    };

    $scope.showMore = function(){
        $scope.offset += $scope.limit;
        $scope.search();
    };

    $scope.hasMore = function(){
        return $scope.more;
    }

    $scope.reset = function() {
        $scope.limit = 10;
        $scope.offset = 0;
        $scope.templates = [];
        $scope.more = true;

        $scope.search();
    }

    $scope.delete = function() {
        var id = this.template.id;
        Template.delete({id: id}, function(){
            $('#template_'+id).fadeOut();
        });
    }

    $scope.sort_order = "title";
    $scope.is_desc = false;

    $scope.reset();
};

List.html:

<form class="form-search">
    <div class="input-append">
        <input type="text" ng-model="query" class="input-medium search-query" placeholder="Search">
        <button ng-click="reset()" type="submit" class="btn"><i class="icon-search"></i></button>
    </div>
    <button ng-click="query=''; reset()" ng-disabled="!query" type="submit" class="btn">Reset</button>
</form>
<p class="sort">
    Sort: 
    <a ng-click="sort('title')">Title</a>
    <span ng-show="sort_order=='title' && is_desc==true"><i class="icon icon-arrow-down"> </i></span>
    <span ng-show="sort_order=='title' && is_desc==false"><i class="icon icon-arrow-up"> </i></span>
    &nbsp;|&nbsp;
    <a ng-click="sort('created_at')">Date Created</a>
    <span ng-show="sort_order=='created_at' && is_desc==true"><i class="icon icon-arrow-down"> </i></span>
    <span ng-show="sort_order=='created_at' && is_desc==false"><i class="icon icon-arrow-up"> </i></span>
</p>
<table class="table">
    <tbody>
        <tr ng-repeat="template in templates" id="template_{{template.id}}">
            <td>{{template.title}}</td>
        </tr>
    </tbody>
</table>
<a ng-show="hasMore()" ng-click="showMore()">Show more</a>
<hr>
<a href="/#/new" class="btn"><i class="icon icon-plus"> </i> New Template</a>

New.html

<h2>New Template</h2>
<form name="new_template">
    <div class="control-group" ng-class="{error: form.title.$invalid}">
        <div class="controls">
            <input type="text" class="span6" ng-model="template.title" name="title" id="title" value="" placeholder="Template name" />
        </div>
    </div>

    <div class="control-group" ng-class="{errors: form.content.$invalid}">
        <div class="controls">
            <textarea name="content" ng-model="template.content" id="content" class="template-content span12" rows="15"></textarea>
        </div>
    </div>
    <div class="form-actions">
        <button ng-click="save()" class="btn btn-primary save-template">Save Template</button>
    </div>
</form>

My layout file:

<!DOCTYPE html>
<html ng-app="MailStash" xmlns="http://www.w3.org/1999/xhtml" xmlns:fb="http://ogp.me/ns/fb#">
    <head>
        <title>MailStash</title>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta name="author" content="Billy Jones - http://theninthnode.com">
        {{ Html::style('css/bootstrap.cerulean.min.css') }}
        @yield('css')
        {{ Html::style('css/style.css') }}
    </head>
    <body class="preview" data-spy="scroll" data-target=".subnav" data-offset="80">
        <div class="container-fluid">
            @include('common.header-fluid')
        </div>
        <div class="container-fluid main">
            <div ng-view></div>
            @include('common.footer')
        </div>

        {{ HTML::script('js/jquery.min.js') }}
        {{ HTML::script('js/bootstrap.min.js') }}
        {{ HTML::script('js/angular.min.js') }}
        {{ HTML::script('js/angular-resource.min.js') }}
        {{ HTML::script('js/jquery.dataTables.min.js') }}
        @yield('scripts')
        {{ HTML::script('js/app.js') }}
        {{ HTML::script('js/main.js') }}
    </body>
</html>

I tried to use:

<div class="row-fluid">
    <div class="span3">
        <div ng-include="'/js/partials/list.html'"></div>
    </div>
    <div class="span9">
        <div ng-include="'/js/partials/new.html'"></div>
    </div>
</div>

But i lost the functionality of these partials. ie the search form stopped working and the new template form stopped working.

like image 979
iamjonesy Avatar asked Apr 14 '13 15:04

iamjonesy


1 Answers

I think what you are saying is you are replacing the <div ng-view></div> with the last block with 2 ng-include .

If so you probably don't need the controller defined in the routing config and need to add ng-controller attributes to the html

like image 168
charlietfl Avatar answered Oct 02 '22 21:10

charlietfl