Handling form submission

We have created posts list page and fetched posts data from real remote APIs.

In before steps,we have created dummy files by gulp component for adding new posts and editing existing post. Let's enrich the content of them.

Add post

Firstly add a savePost method in Post service. It can save a post or update a post.

// Creates or updates an post
  save(post) {

    let request = {};

    // If there's a id,perform an update via PUT w/ post's id
    if (post.id) {
      request.url = `${this._AppConstants.api}/posts/${post.id}`;
      request.method = 'PUT';
      // Delete the id from the post to ensure the server updates the id,// which happens if the title of the post changed.
      delete post.id;

      // Otherwise,this is a new post POST request
    } else {
      request.url = `${this._AppConstants.api}/posts`;
      request.method = 'POST';
    }

    // Set the post data in the data attribute of our request
    request.data = post;

    return this._$http(request);

  }

Replace the content of new-post.controller.js with the following:

class NewPostController {
  constructor(Post,$state) {
    'ngInject';

    this._Post = Post;
    this._$state = $state;
    this.data = { title: '',content: '' };
  }

  $onInit() {
    console.log("initializing NewPost...");
  }

  $onDestroy() {
    console.log("destroying NewPost...");
  }

  save() {
    console.log("saving data @" + this.data);
    this._Post.save(this.data)
      .then((res) => {
        this._$state.go('app.posts');
      })
  }

}

export default NewPostController;

In constructor(),inject Post and $state,here $state is use for change state to route to other components.

save() method calls savePost method of Post service,and when it done successfully,go to state app.posts aka posts component view.

new-post.html:

<div class="page-header">
  <h1>{{'new-post'}} <small>all fields marked with star are required.</small></h1>
</div>
<div class="panel panel-default">
  <div class="panel-body">
    <form id="form" name="form" class="form" ng-submit="$ctrl.save()" novalidate>
      <div class="form-group" ng-class="{'has-error':form.title.$invalid && !form.title.$pristine}">
        <label class="form-control-label" for="title">{{'title'}} *</label>
        <input class="form-control" id="title" name="title" ng-model="$ctrl.data.title" required/>
        <div class="form-control-Feedback" ng-messages="form.title.$error" ng-if="form.title.$invalid && !form.title.$pristine">
          <p ng-message="required">Post Title is required</p>
        </div>
      </div>
      <div class="form-group" ng-class="{'has-error':form.content.$invalid && !form.content.$pristine}">
        <label class="form-control-label" for="content">{{'content'}} *</label>

        <textarea class="form-control" type="content" name="content" id="content" ng-model="$ctrl.data.content" rows="8" required ng-minlength="10">

        </textarea>
        <div class="form-control-Feedback" ng-messages="form.content.$error" ng-if="form.content.$invalid && !form.content.$pristine">
          <p ng-message="required">Post Content is required</p>
          <p ng-message="minlength">At least 10 chars</p>
        </div>

      </div>
      <div class="form-group">
        <button type="submit" class="btn btn-success btn-lg" ng-disabled="form.$invalid || form.$pending">  {{'save'}}
        </button>
      </div>
    </form>
  </div>
  <div class="panel-footer">
    back to <a href="#" ui-sref="app.posts">{{'post-list'}}</a>
  </div>
</div>

There are only two fields in this form,a title input field and a content textarea.

In the template file,the controller is alias as $ctrl,and it uses a ng-submit directive to submit form by calling $ctrl.save() method.

It also includes form validation,title is a required field,and content is required and min-length of the content is set to 10. Here I used ng-minlength directive,the HTML 5 minlength attribute should also work.

Each field has some status to describes input field state change,it Could be valid,invalid,touched,untouched,dirty,pristine.

  • The initial status should be pristine,there is no interaction on the field,when input something it becomes dirty.
  • touched and untouched is designated for touchable device,such mobile,tablet,and touchable LCD etc.
  • valid and invalid indicates validation results applied on related fields.

The status value can be accessed via expression: <form name>.<field name>.$<status>.

For the form,there are also some status values available,such as valid,pending,submitted,pristine etc. It can be accessed by <form name>.$<status>.

And if the form validation Failed,the error info can be gathered via expression: <form name>.<field name>.$error.

With the help of ngMessages,we can decide how to show or hide the validation failure messages.

We can also change the field style to decorate the form group when errors occur. As the following screen,when the form is invalid,the error is shown on the field.

When the form is submitted successfully,it returns to posts list page. A new post is added there.

Edit post

Edit post is very similar with the new post case. The difference is it should load the existing post in the initial stage which can be done in $onInit method of edit-post controller.

edit-post.controller.js:

class EditPostController {
  constructor(Post,$state,$stateParams) {
    'ngInject';

    this._Post = Post;
    this._$state = $state;
    this.id = $stateParams.id;
    this.data = {};
  }

  $onInit() {
    console.log("initializing Edit Post...");
    this._Post.get(this.id).then((res) => this.data = res);
  }

  $onDestroy() {
    console.log("destroying Edit Post...");
  }

  save() {
    console.log("saving data @" + this.data);
    this._Post.save(this.data).then((res) => {
      this._$state.go('app.posts');
    });
  }

}

export default EditPostController;

When route to edit-post,it should accept a id parameter. Inject $stateParams in constructor funcation,all path parameters can be accessed via this object.

In the $onInit method,it calls Post.get() to get a post by id.

Add a get method in Post service.

get(id) {

    let deferred = this._$q.defer();

    if (!id.replace(" ","")) {
      deferred.reject("post id is empty");
      return deferred.promise;
    }
    this._$http({
      url: this._AppConstants.api + '/posts/' + id,method: 'GET'
    })
      .then(
      (res) => deferred.resolve(res.data),(err) => deferred.reject(err)
      );
    return deferred.promise;
  }

The content of edit-post template file is similar with new-post.

<div class="page-header">
  <h1>{{'edit-post'}} <small>all fields marked with star are required.</small></h1>
</div>
<div class="panel panel-default">
  <div class="panel-body">
    <form id="form" name="form" class="form" ng-submit="$ctrl.save()" novalidate>
      <div class="form-group">
        <label class="form-control-label" for="title">{{'id'}}</label>
        <div class="form-control-static" id="id" name="id">
          {{$ctrl.data.id}}
        </div>
      </div>
      <div class="form-group" ng-class="{'has-error':form.title.$invalid && !form.title.$pristine}">
        <label class="form-control-label" for="title">{{'title'}} *</label>
        <input class="form-control" id="title" name="title" ng-model="$ctrl.data.title" required/>
        <div class="form-control-Feedback" ng-messages="form.title.$error" ng-if="form.title.$invalid && !form.title.$pristine">
          <p ng-message="required">Post Title is required</p>
        </div>
      </div>
      <div class="form-group" ng-class="{'has-error':form.content.$invalid && !form.content.$pristine}">
        <label class="form-control-label" for="content">{{'content'}} *</label>
        <textarea class="form-control" type="content" name="content" id="content" ng-model="$ctrl.data.content" rows="8" required ng-minlength="10">
        </textarea>
        <div class="form-control-Feedback" ng-messages="form.content.$error" ng-if="form.content.$invalid && !form.content.$pristine">
          <p ng-message="required">Post Content is required</p>
          <p ng-message="minlength">At least 10 chars</p>
        </div>
      </div>
      <div class="form-group">
        <button type="submit" class="btn btn-success btn-lg" ng-disabled="form.$invalid || form.$pending">  {{'save'}}
        </button>
      </div>
    </form>
  </div>
  <div class="panel-footer">
    back to <a href="#" ui-sref="app.posts">{{'post-list'}}</a>
  </div>
</div>

When post is saved successfully,it returns posts list.

Comment on POST

Another form is adding comment in the post details page. The post details page is too simple,just display the post details,comments and includes a form to add new comment for this post.

post-details.controller.js:

class PostDetailController {
  constructor(Post,$stateParams) {
    'ngInject';

    this._Post = Post;
    this.id = $stateParams.id;
    this.post = {};
    this.comments = [];
    this.newComment = {
      content: ''
    };
  }

  $onInit() {
    console.log("initializing Post Details...");

    this._Post.getWithComments(this.id)
      .then(
      (res) => {
        this.post = res.post;
        this.comments = res.comments
      }
      );
  }

  $onDestroy() {
    console.log("destroying Post...");
  }

  onSaveComment() {
    console.log("saving comment...@");
    this._Post.saveComment(this.id,this.newComment)
      .then((res) => {
        //refresh comments by post.
        console.log('saved comment.');
        this._Post.getCommentsByPost(this.id)
          .then(
          (res) => {
            this.comments = res;
            this.newComment = {
              content: ''
            };
          }
          );
      });
  }

}

export default PostDetailController;

Have a look at the saveComment and getWithComments of Post service.

saveComment(postId,comment) {

    let request = {};

    if (comment.id) {
      request.url = `${this._AppConstants.api}/posts/${postId}/comments/${comment.id}`;
      request.method = 'PUT';
      delete comment.id;

    } else {
      request.url = `${this._AppConstants.api}/posts/${postId}/comments`;
      request.method = 'POST';
    }
    request.data = comment;

    return this._$http(request);

  }

  get(id) {

    let deferred = this._$q.defer();

    if (!id.replace(" ",(err) => deferred.reject(err)
      );
    return deferred.promise;
  }

  getCommentsByPost(id) {

    let deferred = this._$q.defer();

    if (!id.replace(" ","")) {
      deferred.reject("post id is empty");
      return deferred.promise;
    }
    this._$http({
      url: this._AppConstants.api + '/posts/' + id + '/comments',method: 'GET'
    })
    .then(
      (res) => deferred.resolve(res.data),(err) => deferred.reject(err)
    );
    return deferred.promise;
  }

  getWithComments(id) {
    let deferred = this._$q.defer();
    this._$q.all([
      this.get(id),this.getCommentsByPost(id)
    ])
    .then(
      (res) => {
        deferred.resolve({ post: res[0],comments: res[1] })
      }
    );

    return deferred.promise;
  }

post-detail.html:

<div class="page-header">
  <h1 class="text-xs-center text-uppercase text-justify">
    {{$ctrl.post.title}}
  </h1>
  <p class="text-xs-center text-muted">{{$ctrl.post.createdAt|date:'short'}}</p>
</div>
<div class="card">
  <div class="card-block">
    <p>
      {{$ctrl.post.content}}
    </p>
  </div>
  <div class="card-footer">
    back to <a href="#" ui-sref="app.posts">{{'post-list'}}</a>
  </div>
</div>
<div class="card" ng-if="$ctrl.comments">
  <div class="card-block">
    <div class="media" ng-repeat="c in $ctrl.comments">
      <div class="media-left media-top">
        <a href="#">
          <img class="media-object" src="../" alt="...">
        </a>
      </div>
      <div class="media-body">
        <h6 class="media-heading">{{c.createdAt}}</h6>
        <p> {{c.content}}</p>
      </div>
    </div>
  </div>
</div>
<div class="card">
  <div class="card-block">
    <form id="form" name="form" class="form" ng-submit="$ctrl.onSaveComment()" novalidate>
      <div class="form-group" ng-class="{'has-danger':form.content.$invalid && !form.content.$pristine}">
        <!--<label class="form-control-label" for="content">{{'comment-content'}} *</label>-->
        <textarea class="form-control" type="content" name="content" id="content" ng-model="$ctrl.newComment.content" rows="8" required
          ng-minlength="10">
        </textarea>
        <div class="form-control-Feedback" ng-messages="form.content.$error" ng-if="form.content.$invalid && !form.content.$pristine">
          <p ng-message="required">Comment is required</p>
          <p ng-message="minlength">At least 10 chars</p>
        </div>
      </div>
      <div class="form-group">
        <button type="submit" class="btn btn-success btn-lg" ng-disabled="form.$invalid || form.$pending">  {{'save'}}
        </button>
      </div>
    </form>
  </div>
</div>

It is consist of three parts,post detail,comments list and a comment form to add new comment.

Source codes

Check the sample codes.

Getting Started with AngularJS 1.5 and ES6: part 3的更多相关文章

  1. HTML5新增form控件和表单属性实例代码详解

    这篇文章主要介绍了HTML5新增form控件和表单属性实例代码详解,需要的朋友可以参考下

  2. HTML5表单验证特性(知识点小结)

    这篇文章主要介绍了HTML5表单验证特性的一些知识点,本文通过实例代码截图的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  3. amazeui页面分析之登录页面的示例代码

    这篇文章主要介绍了amazeui页面分析之登录页面的示例代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  4. ios – 将视频分享到Facebook

    我正在编写一个简单的测试应用程序,用于将视频从iOS上传到Facebook.由于FacebookSDK的所有文档都在Objective-C中,因此我发现很难在线找到有关如何使用Swift执行此操作的示例/教程.到目前为止我有这个在我的UI上放置一个共享按钮,但它看起来已禁用,从我读到的这是因为没有内容设置,但我看不出这是怎么可能的.我的getVideoURL()函数返回一个NSURL,它肯定包含视

  5. ios – 错误域= NSURLErrorDomain代码= -1003“找不到具有指定主机名的服务器

    当我尝试在设备上运行应用程序时出现此错误.当我在模拟器上运行它并且post请求正常工作时,我没有收到此错误.这是我的代码片段:任何帮助表示赞赏.谢谢解决方法此错误通常会提示DNS相关问题.检查设备上的DNS设置并确认您可以使用Safari或其他浏览器浏览互联网.如果有一个url,你可以在同一台服务器上获取,尝试直接在设备上的Safari中访问它.

  6. ios – Xcode Bot:如何在post触发器脚本上获得.ipa路径?

    我正在使用机器人来存档iOS应用程序,我需要获取.ipa产品路径才能将其发布到我们的分发系统中.机器人设置:并使用脚本打印所有env变量,其中不包含ipa文件的路径.此外,一些变量指向不存在的目录,即:XCS_OUTPUT_DIR这里的env变量输出:除此之外,我还能够确认.ipa文件是在另一个文件夹中创建的(/IntegrationAssets//

  7. ios – 使用CocoaPods post install hook将自定义路径添加到HEADER_SEARCH_PATHS

    解决方法在Podfile中定义一个方法:然后在post_install中调用该方法:

  8. iOS7 Safari中的全屏模式

    我正在使用SenchaTouch开发移动网站.在iOS7Safari中,我无法创建顶级地址栏和下面的工具栏消失了.Sencha过去常常处理iOS6,但iOS7最近的一些变化导致了这个问题.http://java.dzone.com/articles/safari-ios-7-and-html5我阅读了上面的链接&对于HTML5游戏而言,这似乎也是一个问题.一些其他应用程序.适用于iOS6的旧win

  9. ios – 如何使用新的Apple Swift语言发布JSON

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  10. ios – POST请求使用application / x-www-form-urlencoded

    后端开发人员在POST请求中给出了这些说明:>路线:{url}/{app_name/{controller}/{action}控制器和动作应该是小帽子.>API测试链接:http:****************>请求应该使用POST方法.>参数应通过请求内容体(FormUrlEncodedContent)传递.>参数应该是json格式.>参数是关键的.在协议中没有经验5,我搜索并结束了我的代码.

随机推荐

  1. Angular2 innerHtml删除样式

    我正在使用innerHtml并在我的cms中设置html,响应似乎没问题,如果我这样打印:{{poi.content}}它给了我正确的内容:``但是当我使用[innerHtml]=“poi.content”时,它会给我这个html:当我使用[innerHtml]时,有谁知道为什么它会剥离我的样式Angular2清理动态添加的HTML,样式,……

  2. 为Angular根组件/模块指定@Input()参数

    我有3个根组件,由根AppModule引导.你如何为其中一个组件指定@input()参数?也不由AppModalComponent获取:它是未定义的.据我所知,你不能将@input()传递给bootstraped组件.但您可以使用其他方法来做到这一点–将值作为属性传递.index.html:app.component.ts:

  3. angular-ui-bootstrap – 如何为angular ui-bootstrap tabs指令指定href参数

    我正在使用角度ui-bootstrap库,但我不知道如何为每个选项卡指定自定义href.在角度ui-bootstrap文档中,指定了一个可选参数select(),但我不知道如何使用它来自定义每个选项卡的链接另一种重新定义问题的方法是如何使用带有角度ui-bootstrap选项卡的路由我希望现在还不算太晚,但我今天遇到了同样的问题.你可以通过以下方式实现:1)在控制器中定义选项卡href:2)声明一个函数来改变控制器中的散列:3)使用以下标记:我不确定这是否是最好的方法,我很乐意听取别人的意见.

  4. 离子框架 – 标签内部的ng-click不起作用

    >为什么标签标签内的按钮不起作用?>但是标签外的按钮(登陆)工作正常,为什么?>请帮我解决这个问题.我需要在点击时做出回复按钮workingdemo解决方案就是不要为物品使用标签.而只是使用divHTML

  5. Angular 2:将值传递给路由数据解析

    我正在尝试编写一个DataResolver服务,允许Angular2路由器在初始化组件之前预加载数据.解析器需要调用不同的API端点来获取适合于正在加载的路由的数据.我正在构建一个通用解析器,而不是为我的许多组件中的每个组件设置一个解析器.因此,我想在路由定义中传递指向正确端点的自定义输入.例如,考虑以下路线:app.routes.ts在第一个实例中,解析器需要调用/path/to/resourc

  6. angularjs – 解释ngModel管道,解析器,格式化程序,viewChangeListeners和$watchers的顺序

    换句话说:如果在模型更新之前触发了“ng-change”,我可以理解,但是我很难理解在更新模型之后以及在完成填充更改之前触发函数绑定属性.如果您读到这里:祝贺并感谢您的耐心等待!

  7. 角度5模板形式检测形式有效性状态的变化

    为了拥有一个可以监听其包含的表单的有效性状态的变化的组件并执行某些组件的方法,是reactiveforms的方法吗?

  8. Angular 2 CSV文件下载

    我在springboot应用程序中有我的后端,从那里我返回一个.csv文件WheniamhittingtheURLinbrowsercsvfileisgettingdownloaded.现在我试图从我的角度2应用程序中点击此URL,代码是这样的:零件:服务:我正在下载文件,但它像ActuallyitshouldbeBook.csv请指导我缺少的东西.有一种解决方法,但您需要创建一个页面上的元

  9. angularjs – Angular UI-Grid:过滤后如何获取总项数

    提前致谢:)你应该避免使用jQuery并与API进行交互.首先需要在网格创建事件中保存对API的引用.您应该已经知道总行数.您可以使用以下命令获取可见/已过滤行数:要么您可以使用以下命令获取所选行的数量:

  10. angularjs – 迁移gulp进程以包含typescript

    或者我应该使用tsc作为我的主要构建工具,让它解决依赖关系,创建映射文件并制作捆绑包?

返回
顶部