3

I am having the following issue. I have a mini SPA with an option to view products, edit and create.

The SPA I created using the default .aspx page that comes when you add a new Item (Page), into a sharepoint hosted app, this .aspx files come with some markup and they use default.master

In one of my views I have a form, with an ng-click event to save the data locally into my array of products.

The code is not throwing any exception, however I noticed that when using the .aspx page instead of a plain .html page ASP.NET renders another form tag around the entire sharepoint hostead app, and we all know that there can only be a form per page, right? As a result when I use default.aspx my angular js form is stripped out and therefor my ng-click is doing a postback (because the parent form element has runat=server I suppose), and even if the submit method in the controller is called, then my local data is lost after the postback.

This was already asked here but no good answer for me: 2013: How can I use a form in my AngularJS code in the Default.aspx page?

So, there are 2 possibilities: 1. How can I add the sharepoint suitebar links look and feel to a .html file and still keep my angularjs-controlled form working? 2. Is there anyway to remove the aspnet form rendered by Sharepoint in Sharepoint hosted apps?

I paste here the most relevant pieces of my code just for reference as its too long

Index.html

<!doctype html>
<html>
<head>
    <!-- Styles -->
    <link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet" />|
    <link href="../Content/App.css" rel="stylesheet" />

    <!-- Common Libraries -->
    <script src="//code.jquery.com/jquery-2.1.1.min.js" type="text/javascript"></script>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.min.js" type="text/javascript"></script>
    <script src="//code.angularjs.org/1.3.2/angular-resource.min.js" type="text/javascript"></script>
    <script src="//code.angularjs.org/1.3.2/angular-mocks.js" type="text/javascript"></script>
    <script src="../Scripts/lib/angular-ui-router.min.js" type="text/javascript"></script>
    <script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.11.2.js" type="text/javascript"></script>
    <script src="../Scripts/lib/ui-utils.min.js" type="text/javascript"></script>

    <!-- Application Script -->
    <script src="../Scripts/App/App.js" type="text/javascript"></script>
    <!-- Services -->
    <script src="../Scripts/App/Common/Services/common.services.js" type="text/javascript"></script>
    <script src="../Scripts/App/Common/Services/productResource.js" type="text/javascript"></script>
    <script src="../Scripts/App/Common/Services/productResourceMock.js" type="text/javascript"></script>
    <!--Controllers -->
    <script src="../Scripts/App/Products/ProductListCtrl.js" type="text/javascript"></script>
    <script src="../Scripts/App/Products/productDetailCtrl.js" type="text/javascript"></script>
    <script src="../Scripts/App/Products/productEditCtrl.js" type="text/javascript"></script>
</head>

<body ng-app="productManagement">
    <nav class="navbar navbar-inverse">
        <div class="container">
            <a class="navbar-brand"
               ui-sref="home">Acme Product Management</a>
            <div class="navbar-header">
                <button type="button"
                        class="navbar-toggle"
                        data-toggle="collapse"
                        data-target=".navbar-collapse">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
            </div>
            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                    <li><a ui-sref="productList">Product List</a></li>
                    <li>
                        <a ui-sref="productEdit.info({productId:0})">
                            <i class="glyphicon glyphicon-plus"></i>
                            Add Product
                        </a>
                    </li>
                </ul>
            </div>
        </div>
    </nav>

    <div class="container">
        <div ui-view></div>
    </div>
</body>
</html>

ProductEditInfoView.html

<form class="form-horizontal" name="productForm">
    <fieldset>
        <legend>Basic Product Information</legend>
        <div class="form-group">
            <label class="col-md-2 control-label"
                   for="inputProductName">Product Name</label>
            <div class="col-md-4">
                <input class="form-control"
                       id="inputProductName"
                       type="text"
                       placeholder="Product Name"
                       ng-model="vm.product.productName" />
            </div>
        </div>
        <div class="form-group">
            <label class="col-md-2 control-label" for="inputProductCode">Product Code</label>
            <div class="col-md-4">
                <input class="form-control"
                       id="inputProductCode"
                       ui-mask="AAA-****"
                       ng-model="vm.product.productCode">
            </div>
        </div>
        <div class="form-group">
            <label class="col-md-2 control-label"
                   for="inputAvailabilityDate">Availability</label>
            <div class="col-md-4">
                <div class="input-group">
                    <input class="form-control"
                           id="inputAvailabilityDate"
                           type="text"
                           datepicker-popup="MMM dd, yyyy "
                           is-open="vm.opened"
                           ng-model="vm.product.releaseDate" />
                    <span class="input-group-btn">
                        <button class="btn btn-default"
                                ng-click="vm.open($event)">
                            <i class="glyphicon glyphicon-calendar" />
                        </button>
                    </span>
                </div>
            </div>
        </div>

        <div class="form-group">
            <label class="col-md-2 control-label"
                   for="inputDescription">Description</label>
            <div class="col-md-10">
                <textarea class="form-control"
                          id="inputDescription"
                          placeholder="Description"
                          rows="3"
                          ng-model="vm.product.description" />
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-4 col-md-offset-2">
                <span>
                    <button class="btn btn-primary"
                            style="width:80px;margin-right:10px"
                            ng-click="vm.submit()">
                        Save
                    </button>
                </span>
                <span>
                    <button class="btn btn-default"
                            style="width:70px"
                            ng-click="vm.cancel()">
                        Cancel
                    </button>
                </span>
            </div>
        </div>

    </fieldset>
</form>

And ProductController with the submit!(which has a save !

(function () {
    "use strict";

    angular
        .module("productManagement")
        .controller("ProductEditCtrl",
        ["product",
            "$state",
            ProductEditCtrl]);


    function ProductEditCtrl(product, $state) {
        var vm = this;

        vm.product = product;

        if (vm.product && vm.product.productId) {
            vm.title = "Edit: " + vm.product.productName;
        }
        else {
            vm.title = "New Product"
        }

        vm.open = function ($event) {
            $event.preventDefault();
            $event.stopPropagation();

            vm.opened = !vm.opened;
        };

        vm.submit = function () {
            vm.product.$save();
         }

        vm.cancel = function () {
            $state.go('productList');
        }

        vm.addTags = function (tags) {
            if (tags) {
                var array = tags.split(',');
                vm.product.tags = vm.product.tags ? vm.product.tags.concat(array) : array;
                vm.newTags = "";
            } else {
                alert("Please enter one or more tags separated by commas");
            }
        }

        vm.removeTag = function (idx) {
            vm.product.tags.splice(idx, 1);
        }

    }
}());
3

I fought with this for a long time as well as I am very new to both SharePoint app development, AngularJS, and JavaScript....

In your ProductEditInfoView.html, change:

<form class="form-horizontal" name="productForm">

to:

<ng-form class="form-horizontal" name="productForm">

By doing this, ASP.NET will not see an embedded form tag, and therefore will not remove it.

1

Another option, which has worked well for me:

  1. Create an new page in your Site Pages library.
  2. In that page, add a Content Editor Web Part.
  3. Point that Content Editor Web Part to your index.html page, using the "Content Link" property on the Properties panel.

This will display your app as a Web Part on a SharePoint page. It can be the only Web Part, or you can add additional Web Parts around it if you wish.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.